可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have a TextView that has a constraint of min height of 33. The scroll is disabled from the storyboard. The TextView should increase in height based on the content until it reaches the max height of 100. Then I changes the scrollEnabled to true and the height of the TextView to max height of 100, but the height changes to the 33. How can I fix this problem?
import UIKit
class ViewController: UIViewController, UITextViewDelegate {
@IBOutlet weak var messageTextView: UITextView!
let messageTextViewMaxHeight: CGFloat = 100
override func viewDidLoad() {
super.viewDidLoad()
self.messageTextView.delegate = self
}
func textViewDidChange(textView: UITextView) {
if textView.frame.size.height >= self.messageTextViewMaxHeight {
textView.scrollEnabled = true
textView.frame.size.height = self.messageTextViewMaxHeight
} else {
textView.scrollEnabled = false
}
}
}
回答1:
It seems your code requires two changes, and it will work fine.
- Instead of min height of constraint provide max height of 100:
Change code as below:
import UIKit
class ViewController: UIViewController, UITextViewDelegate
{
@IBOutlet weak var messageTextView: UITextView!
let messageTextViewMaxHeight: CGFloat = 100
override func viewDidLoad()
{
super.viewDidLoad()
messageTextView.delegate = self
}
func textViewDidChange(textView: UITextView)
{
if textView.contentSize.height >= self.messageTextViewMaxHeight
{
textView.scrollEnabled = true
}
else
{
textView.frame.size.height = textView.contentSize.height
textView.scrollEnabled = false // textView.isScrollEnabled = false for swift 4.0
}
}
}
回答2:
This follows a similar approach to the accepted answer but ensures the textView
is fully constrained in both height states.
(There's a bug in the accepted answer - using a height constraint with a <=
relation is insufficient to fully constrain the textView
when scrolling is enabled, since in this case the view provides no intrinsicContentSize
. You can see this in IB (with scrolling disabled), or at runtime via view debugging.)
This is all that's necessary:
// In IB, set the relation to `=` and the constant to your desired threshold point
// Notice this is a strong reference (since the constraint may get deactivated)
@IBOutlet var textViewHeightConstraint: NSLayoutConstraint!
func textViewDidChange(textView: UITextView)
{
let isOversize = textView.contentSize.height >= textViewHeightConstraint.constant
textViewHeightConstraint.isActive = isOversize
textView.isScrollEnabled = isOversize
}
There's no need to set frames manually, since in both cases auto-layout has us covered.
回答3:
For an easy way to solve your problem is to change the frame of the textView whenever textViewDidChange invokes. UITextView actually is a UIScrollView. If you have to use constraint, you have to change the constant of the constraint.
Here is my code:
import UIKit
let width = UIScreen.mainScreen().bounds.width
class ViewController: UIViewController, UITextViewDelegate {
var messageTextView: UITextView!
let messageTextViewMaxHeight: CGFloat = 100
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.redColor()
messageTextView = UITextView(frame: CGRectMake(0, 200 - 33, width, 33))
messageTextView.backgroundColor = UIColor.whiteColor()
view.addSubview(messageTextView)
self.messageTextView.delegate = self
}
//
let bottomY: CGFloat = 200
func textViewDidChange(textView: UITextView) {
let formerRect = textView.frame
if formerRect.height > messageTextViewMaxHeight{
}
else{
textView.frame = CGRectMake(formerRect.origin.x, bottomY - textView.contentSize.height, width, textView.contentSize.height)
}
}
}
回答4:
Maybe the code below is a little better.
import UIKit
let width = UIScreen.mainScreen().bounds.width
class ViewController: UIViewController, UITextViewDelegate {
var messageTextView: UITextView!
let messageTextViewMaxHeight: CGFloat = 100
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.redColor()
messageTextView = UITextView(frame: CGRectMake(0, 200 - 33, width, 33))
messageTextView.backgroundColor = UIColor.whiteColor()
view.addSubview(messageTextView)
self.messageTextView.delegate = self
}
//
let bottomY: CGFloat = 200
func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {
if text == "\n"{
let formerRect = textView.frame
let contentSize = textView.contentSize
if contentSize.height < formerRect.height{
//
}
else{
if contentSize.height >= messageTextViewMaxHeight{
//
}
else{
textView.frame = CGRectMake(formerRect.origin.x, bottomY - contentSize.height, width, contentSize.height)
}
}
}
return true
}
}
回答5:
After many many hours of problems with textviews in table view cells, this was the solution that worked for me. I'm using Masonry, but the constraints could be created in IB as well.
Note that the textview delegate is not used. This is advantageous because it doesn't matter whether you change the text programmatically or via user input. Either way layoutSubviews gets called whenever a text view changes its contents.
If you want to have this directly in your view controller you could use viewDidLayoutSubviews
instead of layoutSubviews
.
@implementation TextViewCell
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self){
UITextView *textView = [[UITextView alloc] initWithFrame:CGRectZero];
textView.scrollEnabled = NO;
self.textView = textView;
[self.contentView addSubview:self.textView];
[self.textView mas_remakeConstraints:^(MASConstraintMaker *make) {
make.leading.equalTo(self.contentView.mas_leadingMargin);
make.trailing.equalTo(self.contentView.mas_trailingMargin);
make.top.equalTo(self.contentView.mas_topMargin);
make.bottom.equalTo(self.contentView.mas_bottomMargin);
make.height.lessThanOrEqualTo(@100.0).with.priorityHigh();
make.height.greaterThanOrEqualTo(@30.0).with.priorityHigh();
}];
}
return self;
}
- (void)layoutSubviews{
CGSize size = [self.textView sizeThatFits:CGSizeMake(self.textView.bounds.size.width, 10000)];
self.textView.scrollEnabled = size.height > 100.0;
[super layoutSubviews];
}
@end