skip to Main Content

I want to create UITextView that can resize and scroll at the same time like the ones on Telegram , Instagram or Whats App that allow UITextView to grow up to or 8 lines then you can scroll if you add more text to it I was able to make the UITextView grow to 5 line but if they are more text I can not see since the isScroll property is disabled

my UITextView is inside UIView with two button on the left and right and I would prefer to do it through constrain if that’s possible if not through code is fine too

enter image description here

2

Answers


  1. You can achieve your expected outcome by following steps:

    1. Assign a textView delegate to your controller
    2. Default disable textView scrolling
    3. On textViewDidChange delegate method measure text height according textView frame
    4. Assign appropriate height to textview & enable scroll if content is exceeded (Up to max height in your case 8 line)

    Here below I am attaching code snippet, which may help you:

    let commentViewMinHeight: CGFloat = 45.0 
    let commentViewMaxHeight: CGFloat = 120.0 //In your case it should be 8 lines
    
    func textViewDidChange(_ textView: UITextView) {
         //Calculate text height 
         let size = textView.sizeThatFits(CGSize(width: textView.frame.size.width, height: CGFloat.greatestFiniteMagnitude))
    
         textViewHeightConstraint.constant = size.height.clamped(to: commentViewMinHeight...commentViewMaxHeight)
    
         if textView.contentSize.height < commentViewMaxHeight {
            textView.setContentOffset(CGPoint.zero, animated: false)
            if textView.isScrollEnabled {
               textView.isScrollEnabled = false
            }
         } else {
                if !textView.isScrollEnabled {
                    textView.isScrollEnabled = true
                }
         }
    } 
    
    extension Comparable {
        func clamped(to limits: ClosedRange<Self>) -> Self {
            return min(max(self, limits.lowerBound), limits.upperBound)
        }
    }
    
    Login or Signup to reply.
  2. Sagar‘s answer is great, but I want to enhance it a bit and add some animation to it:

    the steps you need

    • get an outlet to your textView
    • add a height constraint and get an outlet to it
    • implement textViewDidChange delegate method of the textView
    • in textViewDidChange
      • calculate new height using textView.sizeThatFits(size)
      • set the height constraint constant to new height
      • [optional] animate the constraint change to be more user friendly

    here is an example

    class ViewController: UIViewController {
    
        @IBOutlet weak var textView: UITextView!
        @IBOutlet weak var textViewHeightConstraint: NSLayoutConstraint!
    
        let maxTextHeight:CGFloat = 200
        let minTextHeight:CGFloat = 50
    
        let animationDuration:Double = 0.3
    
        override func viewDidLoad() {
            super.viewDidLoad()
            textView.delegate = self
            resizeTextViewToFitText()
        }
    
        func resizeTextViewToFitText() {
            let size = CGSize(width: textView.frame.width, height: .infinity)
            let expectedSize = textView.sizeThatFits(size)
            self.textViewHeightConstraint.constant = max(min(expectedSize.height, self.maxTextHeight), self.minTextHeight)
            self.textView.isScrollEnabled = expectedSize.height > self.maxTextHeight
            UIView.animate(withDuration: animationDuration) {
                self.view.layoutIfNeeded()
            }
        }
    }
    
    extension ViewController: UITextViewDelegate {
        func textViewDidChange(_ textView: UITextView) {
           resizeTextViewToFitText()
        }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search