'Swift 3: UITextView - Dynanmic height - Programmatically

I have a keyboardContainer class (Subclass of UIView / created programmatically so no storyboard) including a UITextView for the user to type messages in. It is used within a Chat log class and set as the inputAccessoryView. I want to dynamically change the height of it when the user is typing.

I searched for answers and found some. However, I didn't get most of them as they didn't work for me.

What do I have to implement to get the effect I want to have?

Thank´s for your help!

EDIT:

First of all thank you for your help!

However, I´m pretty new to coding so I could not solve the issue. I guess it has something to do with the way I created my keyboardContainer class and its constraints...

Here is the relevant code from within my keyboard container class:

 let textField:UITextView = {
    let view = UITextView()
    view.translatesAutoresizingMaskIntoConstraints = false
    view.layer.cornerRadius = 15
    view.layer.masksToBounds = true
    view.font = UIFont.systemFont(ofSize: 15)
    view.backgroundColor = .white
    return view
}()

overried init(frame: CGRect){
super.init(frame: frame)

addSubview(textField)
    textField.leftAnchor.constraint(equalTo: leftButton, constant: 5).isActive = true
    textField.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true

    textFieldHeightAnchor = textField.heightAnchor.constraint(equalTo: heightAnchor, constant: -10)
    textFieldHeightAnchor.isActive = true

    textFieldRightAnchor = textField.rightAnchor.constraint(equalTo: rightAnchor, constant: -85)
    textFieldRightAnchor.isActive = true
}

Inside my ChatLog I´m using this:

 lazy var keyboard: KeyboardContainer = {
    let key = KeyboardContainer()
    key.frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: 45)
    key.sendButton.addTarget(self, action: #selector(handleSend), for: .touchUpInside)
    return key
}()

override var inputAccessoryView: UIView?{
    get{
        return keyboard
    }
}

What do I need to change ? I guess the constraints?



Solution 1:[1]

You can make your textView conform to the UITextViewDelegate and then resize it to it's contentSize.

Make your view controller conform to the delegate

class ViewController: UIViewController, **UITextViewDelegate** { ... 

After that

yourTextView.delegate = self // put that in viewDidLoad()

Then you can implement the textViewDidChange method. That means, every time you enter something into the keyboard, this function is called.

func textViewDidChange(_ textView: UITextView) {


if textView == youTextView {

    let currentHeight = textView.frame.size.height

    textView.frame.size.height = 0 // you have to do that because if not it's not working with the proper content size

    textView.frame.size = textView.contentSize // here you detext your textView's content size and make it resize.

    let newHeight = textView.frame.size.height

    let heightDifference = newHeight - currentHeight // get the height difference from before and after editing

    yourContainerView.frame.size.height += heightDifference

}

}

Solution 2:[2]

Just disable the scrolling. Don't set any other constraints. This might help you with this.

In your viewDidLoad method,

    YourTextView.translatesAutoresizingMaskIntoConstraints = true
    YourTextView.sizeToFit()
    YourTextView.isScrollEnabled = false
    YourTextView.delegate = self
    YourTextView.isEditable = true

Then use UITextViewDelegate and,

func textViewDidChange(_ textView: UITextView) {

    MyTextView.frame = CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: 100)
    MyTextView.translatesAutoresizingMaskIntoConstraints = true
    MyTextView.sizeToFit()
    MyTextView.isScrollEnabled = false

}

This was before the change, enter image description here

This was after, enter image description here

Solution 3:[3]

If you are looking for UITextView like any message app. No need to deal with code you can manage it using constraints only. Seems a better way to do this using constraints rather than deal with more coding.

Here is the step by step explanation of this.

Step : 1

  • Arrange UItextView and UIBUtton inside one UIView and give height constraint to UIView with low priority.

enter image description here

Step : 2

  • Also give height constraint to UITextView with Greater Then or Equal. as image represent it.enter image description here

Step : 3

Now you just have to deal with contentSize and isScrollEnabled as below snippet.

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool{
if (textView.contentSize.height < 150){
    textView.isScrollEnabled = false
   }
   else{
     textView.isScrollEnabled = true
   }
  return true
}

Hope this help you!!

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Matt Harris
Solution 2
Solution 3