Search code examples
swiftuitextviewnslayoutconstraint

Update an UITextView size that is set via NSLayout in Swift 3


I have a variable in my UIViewController that is tied to a constraint setting up the UITextView's height:
var textViewHeight: Int!

Here is the constraint:
self.view.addConstraintsWithFormat(format: "V:|-74-[v0(\(textViewHeight!))]", views: self.textView)

I use this extension:

extension UIView
{
    func addConstraintsWithFormat(format: String, views: UIView...)
    {
        var viewDict = [String: AnyObject]()
        for (index, view) in views.enumerated()
        {
            view.translatesAutoresizingMaskIntoConstraints = false
            let key = "v\(index)"
            viewDict[key] = view
        }
        addConstraints(NSLayoutConstraint.constraints(withVisualFormat: format, options: NSLayoutFormatOptions(), metrics: nil, views: viewDict))
    }
}

I have set up a Notification that triggers when the keyboard shows up. It is triggered correctly (I have a print and it always fires correctly) and the function that is executed includes this code:

if let keyboardSize = sender.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? CGRect {
        print(keyboardSize.height)
        self.textViewHeight = Int(self.view.frame.height-keyboardSize.height-100)
        self.view.updateConstraints()
}

The keyboard's height is printed correctly but the text view's height is not changed.....
Thank you in advance!


Solution

  • Simply setting the constraints once with visual format will not update the constraints later if the variable value (in this case textViewHeight) changes later. So, you'd have to actually set up a constraint via code that can be modified later as the textViewHeight value changes.

    Here are the changes you'd need:

    1: Add a variable to hold a reference to the constraint you'll want to modify later.

    var heightConstraint:NSLayoutConstraint!
    

    2: Create the constraints for your text view individually instead of using the visual format (self.view.addConstraintsWithFormat(format: "V:|-74-[v0(\(textViewHeight!))]", views: self.textView))

    // Add vertical constraints individually
    let top = NSLayoutConstraint(item:textView, attribute: NSLayoutAttribute.top, relatedBy: NSLayoutRelation.equal, toItem:topLayoutGuide, attribute: NSLayoutAttribute.bottom, multiplier:1.0, constant:74.0)
    heightConstraint = NSLayoutConstraint(item:textView, attribute:NSLayoutAttribute.height, relatedBy: NSLayoutRelation.equal, toItem:nil, attribute:NSLayoutAttribute.notAnAttribute, multiplier:1.0, constant:textViewHeight)
    view.addConstraint(top)
    view.addConstraint(heightConstraint)
    

    3: You are probably better off changing textViewHeight to CGFloat since all the values you'll deal with there would be CGFloat values rather than Int.

    4: Where you get the keyboard notification, after you calculate textViewHeight, add the following line:

    self.heightConstraint.constant = textViewHeight
    

    And that should do the trick since now, when textViewHeight changes, the constraint will be updated as well :)