Bubbles, bubbles, bubbles…

Alejandro Megías
Making Tuenti
Published in
5 min readNov 27, 2017

--

Bubbles could mean a pleasurable and relaxing bath or just a great gin for someone.

At Tuenti, when somebody says Bubbles, a huge redesign of our Conversation component comes up. This component is very important for our application. There we place all our contents that we share with another friend or some of them. For example, the text messages I sent to meet you yesterday, the location I had to share with you because you didn’t find me or just the call I made to book the restaurant. More and more content which has to be shown in order to be consumed in easily and pleasant way by the user.

It’s in charge of our awesome designers, no problem for sure! They propose designs which are scalable for all kind of new contents and existing ones but engineers are always aware of those artifacts which have to be implemented in code…

“Too many round corners!”, “Rendering text is gonna hit performance…”, “The scroll won’t be smooth…”

Yeah! Many comments, many complaints but all of us want to get the best approach. We’re talking about UI so let’s see UIKit. It is the framework we based our project on. Starting with this we found some points where performance is seriously affected:

  • Rendering text is expensive.
  • There are many types of cells and most of them are very different, mainly their heights.
  • Adding corner radius can overload the main thread.

Then, we ask ourselves:

  • Should we draw with no XIBs/Storyboards?
  • Shouldn’t we use Autolayout and get every frame?
  • What about the cell height? Calculated by us?

UIKit has been changed a lot but it seems it has been improved very much… IMHO, UIKit performance is getting worse and I don’t know if it matters to someone.

Using the automatic height for cells we can see that the main thread usage is very high and the app is unusable. UILabels with multiline hit the performance even though they don’t have the basic features like phone/URL detection. It seems we will need low-level libraries like CoreText. We still haven’t started the project yet but we found a lot of issues…

We base our project on Model-View-Presenter (MVP). The M and the P have already been solved so let’s go with V, our “dummy” views, with Texture framework which was tested doing a PoC in our funny HackMeUp! and it wasn’t bad :)

Ok, it’s “amazing” but… What is Texture?

“Texture is an iOS framework built on top of UIKit that keeps even the most complex user interfaces smooth and responsive.”

Oooook but… What exactly is Texture?

Basically, Texture is a framework which uses UIKit internally to render the UI of your views optimizing every calculation in the background, that means avoiding using the main thread and loosing FPS. In Texture world, every UI component is a node. They are basically wrappers of the UI component. Nodes offer a very similar interface so it’s an advantage to integrate it. Let’s start with ASTableNode which will replace our UITableView.

We need to create ASCellNodes to represent each content instead of UITableViewCell. ASTableNode can determine the cell node height. Does it mean that it works like UITableView with UITableViewAutomaticDimension? It doesn’t, it does better. In addition, it calculates the heights in background using its Intelligent Preloading feature. It works with three states:

  • Preload: Loads network resources and asynchronous requests in background for cells which don’t appear yet.
  • Display: Maybe it’s the most interesting. Here Texture takes advantage of calculating the cell layout, rasterizing texts and decoding images. And all of them in background.
  • Visible: It belongs to cells which are being presented.

Wow! Everything looks awesome and we don’t need so much to take advantage of these things but… How should we create cells?

Every content we want to represent in the conversation should be a cell. Now, we’re going to create a subclass of ASCellNode. What do we need? What we do NOT need is a graphic interface. We will need to implement its layout with subcomponents like ASTextNode (UILabel wrapper), ASImageNode (UIImageView), even more interesting nodes like ASNetworkImageNode or ASVideoNode. All of them have a lot of amazing features that you can read here. I’m going to explain each step with Call node example:

Call cell node

Analyzing the cell, we can see that it’s composed by several subcomponents:

Decomposed Call node

Let’s define its layout overriding the method:

This method returns the distribution of those subcomponents, how it must be drawn. In this case we have the top content (title) and bottom content (icon, counterpart and time). In addition, we add the player node.

To distribute those elements we can use several Specs that Texture offers. You can find all of them here.

All elements should have intrinsic content size, for example the text content for an ASTextNode or image size for an ASImageNode. But sometimes we don’t have its size, for example for network images which aren’t loading yet, so we can define a preferred size using ASDimension. Yes, preferred and ASDimension. Using preferredSize it will try to set that size and using ASDimension we can establish a size in points or percentage. Then we can set its width to 20% of its parent. These components are very easy to be scaled in different screens and the performance is great.

In addition, there are other interesting properties like minHeight/Width or maxHeight/Width. The Sizing API is really awesome.

What about animations?

We also need to work with animations because they give a good feedback to users. For example, the typing indicator is shown with an animation in order to show that the counterpart is typing some text.

First of all, we have a conditional variable: shown/hide. Depending on this, it will appear below the avatar, from the left edge or it will be removed from the view.

If we want to show/hide the typing indicator we just have to call:

Basically, we need to call transitionLayout method where it will redraw the whole node executing layoutSpecThatFits. In addition, this method will be called and here we will be able to implement the animation if it’s needed.

Using ASContextTransitioning we will get the final/initial positions and then we can calculate the frame we want to animate.

Conclusion

The experience has been very positive. We discovered a great tool to draw user interfaces optimally, as taking care of performance is usually a tedious work.

Teammates keep working on this component developing new contents/nodes, learning Texture very fast. The code is very meaningful even though we don’t have .XIBs/Storyboards.

Although we got a good solution, many things need to be improved like applying some tools that will give a higher performance. More features can be great for our product like ASTableNode prefetching where we will be able to simulate an infinite scroll of content, etc.

--

--