简体   繁体   中英

Resizeable then scrollable UITextView like Telegram

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

在此处输入图片说明

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM