Learn Flutter from UI challenges

Intro

I am a passionate mobile developer on both of Android and iOS platform. I used to not believe in all of the cross-platform frameworks (Ionic, Xamarin, ReactNative,..) but I am here now to tell my story when I meet Flutter, a cross-platform framework.

Inspiration

As a native developer, I feel the pains of UI customization and there’re even more pains in almost cross-platform frameworks. Flutter comes and really makes sense in this aspect.

Flutter builds up all of the UI elements (called Widget) from scratch. There’s no wrapped native views, no web-based ui elements. Like the way game frameworks builds up the world in game (character, enemies, palaces,..), Flutter is based on Skia graphics renderer engine to draw its own UI world. It really makes sense because you have full-control of what you are drawing on screen. That rings a bell in your head, doesn’t it? With me, it sounds like I can create UI customization easier. I try taking some UI challenges to figure it out.

A challenge I think of is shimmer effect. This is a very familiar effect, if that name is not familiar to you, think of the ‘Slide to unlock’ animation when you wake up your iPhone.

How it works

The basic idea is simple. The animation is made up of the movement of a gradient from left to right.

The point is I don’t want to bring up the effect for only text content. This effect is also very familiar as a loading animation in modern mobile applications.

The first naive idea is simply to draw an opaque gradient area in the top of content layout. It works but not a good one. We don’t want our effect make dirty on our white background. The effect need to be only applied for a given content layout.

It’s time to turn to Flutter document and example code to find out how to do it.

My study drives me to a base class called SingleChildRenderObjectWidget which exposes Canvas object. Canvas is an object that is responsible for drawing content on screen and it has an interesting method called saveLayer to “save a copy of the current transform and clip on the save stack, and then creates a new group which subsequent calls will become a part of” (its document said). It’s exactly the feature I need to isolate my shimmer effect on a particular content layer.

Implementation

In Flutter, there’s a good practice to follow. A widget often includes a parameter named child or children that helps us to apply our transforms to descendant widgets. Our Shimmer widget also has a child and it lets us make up whatever layout we want then pass it as a child of Shimmer, Shimmer widget in its turn will only apply the effect for that child.

_Shimmer is our internal class responsible for effect painting. It extends from SingleChildRenderObjectWidget and overrides paint method to do paint tasks. We are going to use saveLayer and paintChild method of Canvas object to capture our child as a layer and draw the gradient on it (with a little magic from BlendMode).

The rest is to make an animation and our effect will really active. There’s nothing special here, we are going to create an animation to translate our Canvas from left to right before the gradient is drawn, it makes the effect of gradient moving.

We create a new AnimationController in _ShimmerState for our animation. Our _Shimmer and _ShimmerFilter class also need a new variable (call it percent) to store result from that animation execution and call markNeedsPaint whenever a new value emitted from AnimationController (it causes our widget repainted). The translation value of Canvas will be calculated form percent value.

Not bad. We’ve just done the shimmer effect with roughly 100 lines of code. That’s the beauty of Flutter.

It’s just beginning. There’re more complex challenges I want to play with Flutter. I will share my results in next posts. Thanks for reading!