Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to change the TextView height dynamicly to a threshold and then allow scrolling?

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
        }
    }
}

enter image description here

like image 833
user3126427 Avatar asked Jul 16 '16 21:07

user3126427


3 Answers

It seems your code requires two changes, and it will work fine.

  1. Instead of min height of constraint provide max height of 100:

Height Constraint for TextView

  1. 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
            }
        }
    }
    
like image 158
Jigaroza287 Avatar answered Nov 20 '22 14:11

Jigaroza287


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.

like image 35
wardw Avatar answered Nov 20 '22 14:11

wardw


Create a class that inherits from UITextView and add the following into the class:

class CustomTextView: UITextView, UITextViewDelegate {

    override init(frame: CGRect, textContainer: NSTextContainer?) {
        super.init(frame: frame, textContainer: textContainer)

        delegate = self
    }

    var maxHeight: CGFloat = 200

    override var intrinsicContentSize: CGSize {
        var size = super.intrinsicContentSize
        if size.height > maxHeight {
            size.height = maxHeight
            isScrollEnabled = true
        } else {
            isScrollEnabled = false
        }
        return size
    }

    override var text: String! {
        didSet {
            invalidateIntrinsicContentSize()
        }
    }

    func textViewDidChange(_ textView: UITextView) {
        invalidateIntrinsicContentSize()
    }

}

Note: - You can initialize maxHeight to infinity and set maxHeight after creating the CustomTextView. This class can be reused anywhere it is needed in the app, and the max height can be modified for different scenarios.

like image 1
Sam Conrad Avatar answered Nov 20 '22 13:11

Sam Conrad