Flutter — Formula One Paging Animation
The finished product
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.
Formula 1 - Drivers Browsing
I've always been a huge fan of Formula 1 motorsport and it was also a big part of my dad's Sunday rituals to make a…
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.
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 is was able to set the image size to 2 screen widths by setting the
Image‘s width property to:
Of course the
ListView scrollDirection is also set to
So now I can scroll the photos, but need to make them snap into place, enter
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.
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
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:
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.
All open source, do with it what you will … https://github.com/tunitowen/f1_animation