Customize animation table view header like app Tiki

Tram Ho


Sometimes when using famous apps, we can see some screens whose header is animated, zoomed in, changed UI structure every time the user scrolls up or down.

For example, the profile screen of the Twitter app:

Or the homepage of the Tiki app:

Or the impressive UI of the Uber Eats app:

This customizing animate header will make the UX of the app new and less boring and monotonous. When at the top, the user can see the entire header, while scrolling down the header shrinks, the app will display more information.

In this article, we will try to mimic the header animation almost like the Tiki app above. Headers will expand or collapse depending on whether the table view is being scrolled up or down.

Getting started

To start, we need to create a UIViewController which contains a UIView and a UITableView . Name the just created UIView Header View and constraint it with top, left and right of the UIViewController , and the height constraint is set to 88 . Similarly, UITableView then set constraint bottom, left, right with UIViewController and top constraint equal to bottom constraint of Header View . As follows:

To change the height of the header view, we need to create an IBOutlet for the height constaint of the Header View . To implement data for table view, need to create IBOutlet for table view as well.

The dummy data for table view is done as simple as follows:

Defining min and max values

Like the example apps above, when new to these screens, the header will initially be displayed with the max height. In this state, the header will have all the necessary UI components. When scolled down, UIs such as title, image, and buttons will be automatically rearranged, shrink to save space, take room to display more content below.

To do this animation, we need to declare maximum values ​​and minimum values ​​that represent the height of the header when expanded or maximum collapse. Let’s add the following class properties:

In the maximum collapse state, the header will have a height equal to half of the initial maximum expand state.

To make sure the header is always maximized when the view controller is displayed, it’s very simple, in the viewWillAppear methods just reset headerHeightConstraint using maxHeaderHeight :

Now we have implemented the maximum expand initialization state of the header. Next comes the animate header when scrolling.

Scrolling up and down

Protocol UIScrollViewDelegate (automatically conform in protocol UITableViewDelegate ) has many useful methods to help us track and handle scroll view scrolling. The first method that we will use here is scrollViewDidScroll(scrollView: UIScrollView) . This method is called every time the scroll position of the table view (scroll view) is changed. You can use the scroll view’s contentOffset.y property to get the current scroll position. From there resize, animate header view.

To determine if the scroll view is scrolling up or down, one simple way is to use another class property ( previousScrollOffset example). Then subtract the current scroll position from the previous scroll position, if less than 0 it means that the scroll view is scrolling up, and if it is less than 0, it is scrolling down.

Assuming the previousScrollOffset property is set to the correct value, the above logic is concretized into the following code:

To set the correct value for previousScrollOffset , simply set it equal to the current scroll position at the end of the method:

After defining the scroll direction, we can calculate and change the height of the header. The Header will collapse proportionally but the scroll view offset changes, so you can use the above scrollDiff variable to calculate the height that needs to be changed. However, the header cannot be expanded or collapsed beyond the max, the min height declared above. So we need to use the functions max, min, abs to calculate and re-limit the height value:

In the code above, the variable newHeight is used to specify a new height for the header based on the scroll direction. This new height value will be applied to headerHeightConstraint if it is different from the current constant.

If we run the project at this time, we can see that there are some unusual behavior appearing every time the scroll view top or bottom is scrolled. This is because the scroll view’s default bounce animation every time the scroll view is dragged outside its content size limit. So the logic that determines the scroll direction up or down above is wrong when the scroll view is bounce like that.

To fix this bug, just add some logic check as follows:

With the update of the scroll direction as above, run the project again, we will see the header expand and collapse smoothly every time we scroll to the top or bottom of the scroll view.

In some cases, when the table view has only a few cells and the scroll view content size is smaller than the height of the screen, we won’t need to collapse the header. Because in this case, including the header and content of the table view, there is still enough space on the screen. So, to prevent header collapse in this exception, we need to check if there is still space to scroll even if the header collapses. Add the following simple code check before the new height calculation logic to fix this case:

Method canAnimateHeader(_ scrollView: UIScrollView) -> Bool :

Stop scrolling while expanding / collapsing

Another thing to do to ensure the animate header goes smoothly is that we have to freeze the scroll view of the scroll view while the header is expanding / collapse. Because in the above code, we have an if statement to check when the new height is different from the constant value of the current headerHeightConstraint so we can rely on that to know when the header is being animate.

Method setScrollPosition(_ position: CGFloat) :

Run the project and verify, every time the header is expanded / collapse, our table view is no longer scrolled and the header is obscured.

Snap header fully expanded / collapsed

This Behavior prevents the header from being hovered between 2 state fully expanded or fully collapsed . Implementing the animation in scrollViewDidScroll is not enough. But UIScrollViewDelegate also has no delegate method called scrollViewDidStop() so we need to combine 2 available methods to determine when the scroll ends.

As the name of the method, scrollViewDidEndDecelerating() tells us when the scroll view stops scrolling after “scrolling” and “decelerating”. And scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) tells when the scroll view stops scrolling after the user lifts his finger. The variable boolean decelerate equals true if the scroll view continues to move after that. Equal to false means the scroll is about to stop.

After determining when the scroll view stops scrolling, we need to create a helper method to implement logic to animate header expand or collapse, with no floating state in between. Header height will have only 2 state max or min. To do this a mid point is computed. If the height of the header is greater than the mid point, the header will be completely expanded. And vice versa will collapse completely the header.

If you run the app immediately, the header will no longer be hovering between min / max height when it stops scrolling in the middle. However, the expand / collapse header when the header exceeds the mid point has no animation, so it looks very jerky.

Add and replace animation with the following code:

Animating elements within the header

In this section, we will animate, change the position, structure, and arrangement of UI elements in the view header.

In the storyboard, embed the Header View into a new UIView , named the Header View Container . Set top constraint of Header View Container with top constraint of super view (not with safe area), left, right with safe area, bottom with top of UITableView . Set the color of the container view to match the existing header view. The goal is to cover and fill the same color on the status bar.

Constraint of the header view is updated again: top with top of view controller, left, right, bottom with left, right, bottom of container.

Next add UIImageView , UIButton and UITextField and constraint as follows:

When collapsing header view, we will fade the image view and change the constant trailing constraint of the text field. So we need to create IBOutlet for them in the view controller. The rest of the UI elements like 2 buttons are fixed in the top right position, unchanged. The text field will shrink but remain at the bottom left position.

In addition to calculate the shrinkage of the text field so that it is equal to min x of the chat button, we still need to create an IBOutlet for this chat button.

The updateHeader() method to perform animate UI element in the header is as follows:

Finally, call this method updateHeader() in viewWillAppear() , collapseHeader() , expandHeader() and scrollViewDidScroll() :


Share the news now

Source : Viblo