Flutter — Formula One Paging Animation

Tony Owen
3 min readJun 4, 2019

The finished product

https://www.youtube.com/watch?v=FiJQdFeo8kk

It’s been a while since I did one of these. As a big F1 fan, when I saw this awesome Dribbble by Pontus Wellgraf, I had to try and make it in Flutter.

Imagery

The design calls for the driver to be half on screen, luckily the imagery on formula1.com has all the drivers centered. So the next step was to get them into a pager to nicely swipe.

Paging

At first I went for a PageView widget. This sort of worked, but gave me problems. The image needs to take up 2 screen widths to make sure the driver is in the middle. My first attempt was to change the viewportFraction to 2.0 in a PageController. This worked, but not for the first page .. and if memory serves me the last too. After playing with various settings, I came to the conclusion that instead I needed to use a ListView.

With the ListView is was able to set the image size to 2 screen widths by setting the Image‘s width property to:MediaQuery.of(context).size.width*2.

Of course the ListView scrollDirection is also set to Axis.horizontal.

So now I can scroll the photos, but need to make them snap into place, enter ScrollPhysics.

To cut a long story short, I needed to snap to every second page. The easiest way I found was to copy the PageScrollPhysics class and make a couple of adjustments. See F1ScrollPhysics in the repo. Once that was applied the pages snap correctly and all is well.

Animation

Onto the fun part, the character animations.

The first part is figuring out how far we have scrolled, from which driver and to which driver. To do that I added a ScrollController to the ListView. Adding a listener gives us updates every time the ListView scrolls.

As we are scrolling 2 pages at a time, some maths is required to know where we are:

_scrollController.offset / (MediaQuery.of(context).size.width * 2)

This will give us a fractional position of where we are, so 0.5 is half way between item 0 and item 1.

Changing the driver number

Starting on the driver number seemed like a sensible choice, it’s always an Integer. As we get updates very often from the ScrollController, we should just be able to change the String and update State as we go. No Animation Controller needed.

We need to get the last driver number and the next driver number. To do this I used floor and ceil on the pageFraction. Once we have these we can then use pageFraction%1 to know how far between we need to be, and calculate with:

lastDriverNumber-((lastDriverNumber-nextDriverNumber)*currentFraction).round()

Applying this to State, gives us the required effect. The number changes as we scroll.

Changing the rest

Next we need to change the driver’s first name, last name, and team. As these are characters … its a bit more complicated, but not too much.

First I created a string with all characters (only used the English alphabet, sorry Mr Räikkönen). All chars in upper case, lower case, and a space. This was enough for the proof of concept. Obviously more would be needed in reality.

I used the same calculations as the driver number, then found the characters between using this string and the fraction. See the _calculateCharacters in the repo for more details.

The Repo

All open source, do with it what you will … https://github.com/tunitowen/f1_animation

The End

--

--