30

I have a UITextView not scrollable with auto layout set by interface builder, and the text increase or decrease dynamically with no problem, but i want know what is the new UITextView height after setting text, i'm trying to do this:

NSLog(@"text before: %.2f",self.myText.frame.size.height);
[self.myText setText:self.string];
NSLog(@"text after: %.2f",self.myText.frame.size.height);

this is the result:

text before: 47.50
text after: 47.50

the text is increased in the view when i run it, but the size is the same, how i can get the real height after setting text?

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
Piero
  • 9,173
  • 18
  • 90
  • 160
  • I am facing a issue where my textview does not grow larger to accomodate bigger texts, could you please share the steps you followed to achieve this? – Gaurav Abbi Apr 30 '15 at 14:25
  • relevant: `TextViewHeightConstraint.constant = [TextView intrinsicContentSize].height` Also don't forget to uncheck scrolling!! – Fattie Jul 02 '16 at 15:30
  • This has been answered in the link below: https://stackoverflow.com/a/56156621/6386213 – Bhagyesh May 19 '19 at 12:00

14 Answers14

96

All you have to do is:

  • set up all your constraints except the height one AND
  • set textView's scrollEnabled property to NO

The last part is what does the trick.

Your text view will size automatically depending on its text value.

Bruno Bieri
  • 9,724
  • 11
  • 63
  • 92
Pavel Gurov
  • 5,587
  • 3
  • 26
  • 23
34

If you prefer to do it all by auto layout:

In Size Inspector:

  1. Set Content Compression Resistance Priority Vertical to 1000.

  2. Lower the priority of constraint height for your UITextView. Just make it less than 1000.

enter image description here

In Attributes Inspector:

  1. Uncheck Scrolling Enabled.
Michael Revlis
  • 1,463
  • 11
  • 14
13

I have used the code given on following link AutoLayout with Dynamic UITextView height and it worked for me :)

saiday
  • 1,290
  • 12
  • 25
Parul Garg
  • 355
  • 3
  • 14
  • 4
    This is a link-only answer, could you summarize the contents of the link in your answer? – Flimm Oct 07 '16 at 16:02
  • 1
    This is working for my message designing. but I need only increase for four lines after the four lin. textView stop the height increase and scroll. anyone knowns please answer or share the link. – Abishek Thangaraj Nov 09 '20 at 06:26
12

This should work:

NSLog(@"text before: %.2f",self.myText.frame.size.height);
[self.myText setText:self.string];
[self.myText layoutIfNeeded]; // <--- Add this
NSLog(@"text after: %.2f",self.myText.frame.size.height);

Here's an example implementation on my Github: https://github.com/guillaume-algis/SO-27060338

Guillaume Algis
  • 10,705
  • 6
  • 44
  • 72
8

Swift 3.0

textView.isScrollEnabled = false

This allow AutoLayout to do its job.

Marco Martignone
  • 1,231
  • 11
  • 10
  • 2
    That's essentially the only thing that's needed. I've added the textView in Interface builder, so I had to uncheck the "Scrolling Enabled" in IB in identity inspector of the `UITextView`. Also, the only constraints I've added were the top, leading and trailing. So that the height was not defined by constraints, those allowing the size to change automatically. – Andrej May 05 '17 at 21:34
7

Use below code:

Objective-C Code

[textView setScrollEnabled:NO];

Swift Code

textView.isScrollEnabled = false
Alok
  • 24,880
  • 6
  • 40
  • 67
3

Just after changing the text call

[self.myText sizeToFit];
Pang
  • 9,564
  • 146
  • 81
  • 122
merocode
  • 116
  • 2
  • 5
2

Unlike UILabel, UITextView's has no intrinsic size property. So how I did it was set up the UITextView's height constraint, hook it via IBOutlet, and change its value in textViewDidChange or when text changes.

@IBOutlet weak var textViewHeight: NSLayoutConstraint!

func textViewDidChange(textView: UITextView) {

    // dynamic height adjustments

    var height = ceil(textView.contentSize.height) // ceil to avoid decimal

    if height != textViewHeight.constant { // set when height changed
        textViewHeight.constant = height
        textView.setContentOffset(CGPointZero, animated: false) // scroll to top to avoid "wrong contentOffset" artefact when line count changes
    }
}
Hlung
  • 13,850
  • 6
  • 71
  • 90
  • but when you typing you should see end of the text. scroll to bottom with next line of code: textView.setContentOffset(CGPoint(x: 0, y: textHeight - textView.bounds.size.height), animated: true) – Roman Filippov Jan 15 '18 at 12:42
  • @RomanFilippov It's a bit trickier than that though. You could be moving the text input cursor to the top and and add new text there. Which means new text can be added anywhere. I guess one missing piece is detecting where the text is inserted and scroll to there instead, which can be top, or bottom, or somewhere in the center. – Hlung Jan 17 '18 at 03:25
1
- (void)textViewDidChange:(UITextView *)textView
{
    UIFont *myFont = [UIFont systemFontOfSize:14];
    CGSize size =   [self sizeOfText:textView.text widthOfTextView:TextviewWidth withFont:myFont];
    NSLog(@"Height : %f", size.height);
}

-(CGSize)sizeOfText:(NSString *)textToMesure widthOfTextView:(CGFloat)width withFont:(UIFont*)font
{
    CGSize ts = [textToMesure sizeWithFont:font constrainedToSize:CGSizeMake(width-20.0, FLT_MAX) lineBreakMode:NSLineBreakByWordWrapping];
    return ts;
}
Hardik Kardani
  • 576
  • 3
  • 24
1

select textview and uncheck "Scrolling enabled"

select textview from top menu "Editor > size to fit content"

select the view below it, set its top constraints with the textview bottom to whatever margin you want, then go to "Size Inspector",double click or edit the constraint you just added, and set the "Relation" to "Greater than or Equal"

1

Yet another approach is to use

myTextView.textContainer.heightTracksTextView = true

Which allows scroll to be enabled

Henmyg
  • 11
  • 1
1

Well, I haven't converted this code into swift4 syntax, but the logic will remain the same. This is an extension method for Xamarin.ios(C#).

public static nfloat GetEstimateHeight(this UITextView textView, UIView View)
{
    var size = new CoreGraphics.CGSize(View.Frame.Width, height: float.PositiveInfinity);
    var estimatedSize = textView.SizeThatFits(size);
    return estimatedSize.Height;
}

The logic here that will work for swift is

var size = new CoreGraphics.CGSize(View.Frame.Width, height: float.PositiveInfinity);
    var estimatedSize = textView.SizeThatFits(size);
    var textViewFinalHeight = estimatedSize.Height;
Shanu Singh
  • 365
  • 3
  • 16
0

Just an addition as per @Pavel Gurov's answer. If you already set up your height constraint, simply make it inactive. Also worth to call .sizeToFit() afterwards to make sure resize action is performed.

theTextViewHeightConstraint.isActive = false

theTextView.isScrollEnabled = false
theTextView.text = "some text"
theTextView.sizeToFit()
novalagung
  • 10,905
  • 4
  • 58
  • 82
0

the textview height increase by using pure swift code design. I am just do coding part only.

I take this idea from https://stackoverflow.com/a/45071002/9110213

First thing create the textView

    import UIKit
    
    class TextFieldCell: UITableViewCell {
        
        lazy var btnEdit: UIButton! = {
          
          let button = UIButton()
          button.translatesAutoresizingMaskIntoConstraints = false
          button.addTarget(self, action: #selector(self.actionEdit(_:)), for: .touchUpInside)
          button.setTitle("Edit", for: .normal)
          button.titleLabel?.font = UIFont(name: "ProximaNova-Medium", size: 18)
          button.setTitleColor( UIColor(red: 0.29, green: 0.56, blue: 0.89, alpha: 1), for: .normal)
          button.titleLabel?.textAlignment = .left
          return button
          
        }()
      
      lazy var separatorView: UIView! = {
        
        let view = UIView()
        view.translatesAutoresizingMaskIntoConstraints = false
        return view
        
      }()
      
      lazy var textView: UITextView! = {
        
        let textView = UITextView.init(frame: .zero)
        textView.translatesAutoresizingMaskIntoConstraints = false
        textView.delegate = self
        textView.isScrollEnabled = false
        return textView
        
      }()
      
      lazy var titleLabel: UILabel! = {
        
        let label = UILabel(frame: CGRect(x: 27, y: 318, width: 27, height: 12))
        label.text = "Name"
        label.font = UIFont(name: "ProximaNova-Medium", size: 10)
        label.textColor = UIColor(red: 0.61, green: 0.61, blue: 0.61, alpha: 1)
        label.textAlignment = .left
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
        
      }()
        
      
      deinit {
        self.titleLabel = nil
        self.textView = nil
        self.separatorView = nil
        self.btnEdit = nil
      }
        
      override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        
        self.selectionStyle = .none
        
        self.addView()
        self.setConstraint()
        
      }
      
      required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
      }
      
    }
    
    extension TextFieldCell {
    
      func addView(){
        
        self.contentView.addSubview(self.btnEdit)
        self.contentView.addSubview(self.titleLabel)
        self.contentView.addSubview(self.textView)
        self.contentView.addSubview(self.separatorView)
    
      }
      
      func setConstraint(){
        
       // This part is very important to increase the textview height dyamically   

        let textViewHeight = self.textView.heightAnchor.constraint(equalToConstant: 27)
        textViewHeight.priority = .defaultHigh
        self.textView.setContentCompressionResistancePriority(.required, for: .vertical)
        self.textView.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal)
    
        NSLayoutConstraint.activate([
          
          self.titleLabel.leadingAnchor.constraint(equalTo: self.contentView.leadingAnchor, constant: 27),
          self.titleLabel.topAnchor.constraint(equalTo: self.contentView.topAnchor, constant: 38),
          
          self.textView.topAnchor.constraint(equalTo: self.titleLabel.bottomAnchor, constant: 9),
          self.textView.leadingAnchor.constraint(equalTo: self.titleLabel.leadingAnchor),
          textViewHeight,
          self.textView.trailingAnchor.constraint(equalTo: self.btnEdit.leadingAnchor, constant: -25),
    
          self.btnEdit.centerYAnchor.constraint(equalTo: self.textView.centerYAnchor),
          self.btnEdit.widthAnchor.constraint(equalToConstant: 40),
          self.btnEdit.trailingAnchor.constraint(equalTo: self.contentView.trailingAnchor, constant: -33),
          
          self.separatorView.topAnchor.constraint(equalTo: self.textView.bottomAnchor, constant: 10),
          self.separatorView.heightAnchor.constraint(equalToConstant: 1),
          self.separatorView.bottomAnchor.constraint(equalTo: self.contentView.bottomAnchor),
          self.separatorView.leadingAnchor.constraint(equalTo: self.contentView.leadingAnchor, constant: 27),
          self.separatorView.trailingAnchor.constraint(equalTo: self.contentView.trailingAnchor, constant: -15),
          
        ])
        
      }
      
    }
    
    extension TextFieldCell {
    
         @objc func actionEdit(_ sender: UIButton) {
            
        }
      
    }
    
    extension TextFieldCell: UITextViewDelegate {
      func notifyViewController(text:String){
        
      }
      func textViewDidEndEditing(_ textView: UITextView) {
        
      }
    }