Updating Constraints Dynamically
The animated effects in IOS apps you probably took for granted
The “animation” you see below is — rather anticlimactically — the effect of simultaneously inserting time stamps into a TableView, increasing the TableView’s height, and repositioning its relative Views.

More technically, let’s start by talking about constraints. A constraint is ultimately a linear expression that can either be set up using Xcode’s Interface Builder or written programmatically. When the values of this expression changes, or needs to be changed or removed, the system needs to be notified of the change. This is because the initial setup of the constraints are only done in the View Controller’s viewDidLoad method (run once in the View Controller’s lifetime) and will stay that way unless it is told otherwise. Thus, when a constraint change is made in your code, a layout pass is scheduled or forced immediately depending on the method you call.
1. Determine which constraints you will be changing
Changing a constraint means you must first have a handle of the constraint that is accessible to the function in which you will be making the change (in our case, we want our function addTimeStamp() to have access to this constraint handle). This usually means setting a variable in the global scope of your View Controller class. We will be updating our tableView’s height, so set a variable of type NSLayoutConstraint to nil. Add as many constraint handles as you will be manipulating.
var tableViewHeight: NSLayoutConstraint? = nil2. Initial setup — viewDidLoad()
In your initial setup, take into account the changes that can happen to your View. When the updates take place, how will the Views around it lay out? For example, we want to make sure that our “Add Stamp” button does not stay fixed to the top of our View and cover our tableView.

let views = [
"view" : backgroundView,
"tableView": tableView,
"btn": btn
]
NSLayoutConstraint.activate(
NSLayoutConstraint.constraints(withVisualFormat: "H:|-15-[view]-15-|", options: [], metrics: nil, views: views) +
NSLayoutConstraint.constraints(withVisualFormat: "V:|-80-[view]-15-[btn(30)]", options: [], metrics: nil, views: views) +
NSLayoutConstraint.constraints(withVisualFormat: "H:|-15-[btn]-15-|", options: [], metrics: nil, views: views) +
NSLayoutConstraint.constraints(withVisualFormat: "H:|-15-[tableView]-15-|", options: [], metrics: nil, views: views) +
NSLayoutConstraint.constraints(withVisualFormat: "V:|[tableView]|", options: [], metrics: nil, views: views)
)tableViewHeight = NSLayoutConstraint(item: tableView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: CGFloat(rowHeight*stamps.count))
view.addConstraint(tableViewHeight!)
3. The add button — WHERE THE MAGIC HAPPENS
Initialize your UIButton as follows so that it calls the function addTimeStamp() when tapped:

The addTimeStamp() function handles the animation block which updates our predefined tableViewHeight constraint over a duration of 0.7 seconds.
func addTimeStamp(_ sender : UIButton) {// Create the Time Stamp string
let date = Date()
let formatter = ISO8601DateFormatter()stamps.append(formatter.string(from: date)) // append the time stamp string to our stamps array
tableView.reloadData() // update the tableView with the new stamps array
self.view.layoutIfNeeded() // make sure previously queued changes are completed
UIView.animate(withDuration: 0.7, animations: {
self.tableViewHeight?.constant = CGFloat(self.rowHeight*self.stamps.count)
self.view.layoutIfNeeded()
})
}
Choosing your update method
Two primary methods exist for the purpose of updating the layout of your View: layoutIfNeeded() and setNeededLayout(). Counterintuitive to their names, layoutIfNeeded is executed immediately, while setNeededLayout() queues the update for the main loop’s next update cycle. For this reason, the constraint update using the setNeededLayout() method will not appear animated even though it is inside an animate block.


Final result
You can find the complete code for this example here.
