[Flutter] PageView Builder with Animation

Thế Dũng
5 min readSep 11, 2021

--

Before going to the technical content, let’s see what we gonna build.

Overview

So that is the overview of what this article for. Some technique will be found in this post:

  • Provider (For state management)
  • PageView.builder
  • Transform with Matrix4.identify()

The source code can be found here.

Before we start

Goto pubspec.yaml file and add provider package:

dependencies:    flutter:      sdk: flutter    cupertino_icons: ^1.0.2    provider: ^6.0.0 # Add this line

Then save file and run flutter pub get in the terminal.

Let’s code

First step, open the main.dart file and make it display HomeScreen

With home: parameter, we provide it with an HomeScreen object. This is the first screen when the app startup.

After this step, we can get an empty screen when the app startup.

Second step: Create first layout for screen using Column

Remember to add internet permission to allow this app using phone’s network.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.example.page_animation"><uses-permission android:name="android.permission.INTERNET" /> # Add # this line
...

With the header view, you can find it here. Because it’s just a layout file, so I won’t have any explanation for this.

Third step: Using provider

We use this class for setting new value and notify for re-rendering view when the PageView change it’s page value.

Fourth step: Create data class

Each item in PageView will need to be provide a data object. Like title, image’s url, … So I have create an example class here. Again, it’s just a data class, nothing special so I will not have any comment here.

Fifth step: Create HomeItem

I haven’t put any Transform or matrix here. Just normal layout.

Sixth step: Continue building HomeScreen:

Return to HomeScreen, I placed some comments with the source code in the snippet bellow:

Here you will have error with DataUtils class, I added some dummy data using this class. It’s here for you.

Then, you can hot reload the app and this is the result:

Seventh step(final step): Adding animation

As you can see from the first .gif image, 2 side-items are smaller than the center. So we need to do a Transform here.

Before going to how to make item scale, I want to show you the Transform widget first. The idea of this is make the child widget become a matrix. Then we will apply some technique with an identify matrix (matrix i)

This matrix in form of 4x4 matrix with the diagonal line is made of 1:

index: x =  0 1 2 3  y =
[1 0 0 0] 0
[0 1 0 0] 1
[0 0 1 0] 2
[0 0 0 1] 3

To change any value of this 4x4 matrix, you need to provide the coordinates in form (x, y). If you want to change the last number in the first line, it should be (3, 0)

In Flutter, you don’t have to write entire 4x4 matrix like the example above, You can get that matrix from Matrix4.identify(). Then when you have that matrix, call function setEntry(x, y, value) to change any value in the matrix.

It will look like this:

return Transform(transform: Matrix4.identity()
..setEntry(3, 3, scaleValue)
..setEntry(0, 3, distance * gauss * diff.sign),
alignment: FractionalOffset.center, child: Card( elevation: 8, margin: EdgeInsets.symmetric(vertical: 16.0),
...

Now we know how to set value into the Matrix4.identify(). But Which position would we change? For this post I need to change 2 things

  • Scale value
  • The space between each item

With the first one, I will change the (3, 3) position’s value. When it = 1 → Scale = 1 → The normal widget, no scale. To scale up, change the value to less than 1. And scale down, change the value to greater than 1.

For the second one, I will change their x position (x is in horizontal dimension, y is vertical dimension). So I pick the (0, 3) position and change it’s value.

How can I know which position to choose? You can read it here: https://medium.com/flutter-community/advanced-flutter-matrix4-and-perspective-transformations-a79404a0d828

Now you know which position need to be changed. Then which value can we set for those positions. It’s a little bit of Math here.

For the scale:

double page = Provider.of<PageViewHolder>(context).page;double diff = index - page;double scaleValue = 1 + diff.abs() * 0.1;

The first line, I get the value of PageViewHolder (Get the instance of PageViewHolder what we created in HomeScreen and provided it to ChangeNotifierProvider<PageViewHolder>.value

  • page is the current page value of PageView (This value is in double number. Run from last page → current page (0.0–0.1–0.2…1.0)
  • index: The item index (0 , 1, 2, 3, …)
  • diff: index — page
  • scaleValue: I have this formula by trying to change some value, several times and choose the one I feel ok.

For sliding page item:

double gauss = exp(-(pow((diff.abs() - 0.5), 2) / 0.08));double distance = 32;
...
..setEntry(0, 3, distance * gauss * diff.sign)

First line, I use gaussian formula to make the space between look not too boring. It will have this kind of form:

You can search for this in google, a lot of article explain how to calculate a gaussian function.

And if you look closer to the first screen animation, you can see the text is move a bit from right to left when I navigate to the next page. This will be archived by using Transform.translate

In this Transform.translate widget, you need to provide an offset object. It can be created by using Offset(dx, dy). Here I just want the text to slide a small distance. So this is my formula:

offset: Offset(distance * diff, 0),

The entire file for this item here.

Everything’ve been set. Now you can run the application and figure out more animation from changing value of this demo app.

Hope that you had a great of reading time.

Thanks for reading. Leave a comment if you have any question, hit the clap to make me happy. Thanks a lot!

--

--

Thế Dũng
Thế Dũng

Written by Thế Dũng

Software engineer - Mobile developer

No responses yet