[Swift❤️] Implementing Twitter iOS App UI
A complete guide to implement the Twitter iOS app Profile UI in Swift
It’s been the fourth year since I first started writing a HelloWorld on iOS 📱
Before that I was an Android developer, and at that time Twitter was literally my top 5 application, if not the 1st, I have ever seen in Android, considering it’s blazingly smooth user interface and wonderful interactivity.
When I moved to the iOS, Twitter app has always been my references whenever I worked on any projects. The vivid layout transition, interactive scrolling animations and wonderful performance is without a doubt the benchmark in mobile app community.
[reason to make this guide]
tho I am not the only one talking about twitter-ui-how-to, but I promise this will be “the search is over” guide if you are looking for a serious one.
What will be covered ?
This guide will cover mainly the idea and design concepts, instead of codes, which you could check out an even more detailed implementation guide with code example on Github.
First talk about the obvious stuff that everyone expects:
- Sticky Profile Header with interactive blurring animation
- Interactive layout changes when scrolling
- Packing up all the views (Navigation, ProfileHeader, TableView(s), and more), and more importantly — the advantages and disadvantages of different ways to structure all those views
And followed with the tiny, yet significant, details that differentiate your apps from others. Keep it discussed later : )
I am not a native English speaker and in case you prefer talking in Swift — here is the github project available on Github/iOS-TwitterProfile :)
1 ⭐️ = 1 support ; ( and letting me know that someone is actually reading the article and find it useful because it takes hours and hours to prepare the materials and ……and …… and ….. )
Lets keep calm and get your hands dirty : )
Design Concept, Overview
Everything is packed in a UIScrollView
The idea of making the Twitter Profile is to embed all the views’ container in a single UIScrollView (MainScrollView).
Other possible (but not so good) attempts
At the very first thought I tried to do it all by using the UITableView.headerView api, but there are obvious reasons not to do it in this way:
- Since there are multiple segments (tweets, photos, favorites), what if the photos or favorites segment are not UITableView ?
- Even if all the segments are displayed in UITableView, the computation cost for changing the dataSource upon each segmentControl changes are too expensive. When you change a dataSource inside a UITableView, you are simply destroying all the cells and create new cells at the same time, which degrades the UI performance severely because of the laggy transition.
The second attempt is by separating three segments into three ContaineViewController. The advantage for doing so is that the codes for each segments (logic, dataSource, layout) could be separated into three viewControllers, and then embedding them all in a parenViewController. That result works perfectly fine but it generates noticeable amount of repeating codes and makes the scrolling state much harder to sync between each viewController.
The idea of making the Sticky Header is really simple — magic happens with UIScrollView.contentOffset. You can imagine each of the UI elements inside the UIScrollView is described as a function of contentOffset.y
Basically most of the things happen in the above three functions. Be aware that scrollViewDidScroll() suppose to be called upon every pixels user scrolled on mainThread, heavy computation should be avoided.
I said “suppose to be called” because it’s not guaranteed to be called in every pixel scrolled. Which means sometimes you will not reach a point that contentSize.y == a specific value since it’s skipped certain frames when fast scrolling. It’s very important to double check if the states of each animation is properly reset at boundary (min, max).
For example, sticking a header always on top of scrollView when bouncing is as simply as setting the view.frame to CGRect(0, contentOffset.y, width, height). This is set inside the scrollViewDidScroll().
The way to set all the other views’ animation with respect to UIScrollView.contentOffset.y are more or less the same, with more conditions and slightly more Maths. Check out the full example on Github is recommended.
Since all UI elements are wrapped in a single UIScrollView, but we want the scrollView indicator (highlighted in red) to be appeared only on child tableViews. Here is the trick to achieve the same effect as if in the official Twitter app:
This effectively make the scrollIndicator frame below desired location.
The official Twitter Profile is of course much much more than what we discussed here, like dynamic cells, a more fancy blurring, etc.
I will consider adding more advanced implementation into the project such as integrating AsyncDisplaykit to support self-sizing cell — if there are positive feedbacks (likes and stars 😃) for this guide !
Don’t forget to check out the Github project for more detailed implementation 👍🏻