Adding Custom Transitions to PageViews

Let’s discuss adding a few custom transition to the pages using Transform + PageView . This part will use the Transform widget extensively and I recommend reading one of the multiple articles on the widget.

My recommendations would be the Deep Dive I wrote and WM Leler’s Transform article.

Transition 1

The setup

We first use a basic PageView.builder

PageView.builder(

controller: controller,

itemBuilder: (context, position) {

},

itemCount: 10,

)

Let’s have 10 items for now.

We use a PageController and a variable which holds the value of the currentPage .

Defining the PageController and variables:

PageController controller = PageController();

var currentPageValue = 0.0;

Updating the variable when the PageView is scrolled.

controller.addListener(() {

setState(() {

currentPageValue = controller.page;

});

});

Finally, we construct the PageView .

Now, let’s check for three conditions:

If the page is the page being swiped from If the page is the page being swiped to If the page is a page off screen

PageView.builder(

controller: controller,

itemBuilder: (context, position) {

if (position == currentPageValue.floor()) { } else if (position == currentAnimationValue.floor() + 1){



} else {



}

},

itemCount: 10,

)

Now we return the same page but wrapped in a Transform widget to transform our pages when we swipe it.

PageView.builder(

controller: controller,

itemBuilder: (context, position) {

if (position == currentPageValue.floor()) {

return Transform(

transform: Matrix4.identity()..rotateX(currentPageValue - position),

child: Container(

color: position % 2 == 0 ? Colors.blue : Colors.pink,

child: Center(

child: Text(

"Page",

style: TextStyle(color: Colors.white, fontSize: 22.0),

),

),

),

);

} else if (position == currentPageValue.floor() + 1){

return Transform(

transform: Matrix4.identity()..rotateX(currentPageValue - position),

child: Container(

color: position % 2 == 0 ? Colors.blue : Colors.pink,

child: Center(

child: Text(

"Page",

style: TextStyle(color: Colors.white, fontSize: 22.0),

),

),

),

);

} else {

return Container(

color: position % 2 == 0 ? Colors.blue : Colors.pink,

child: Center(

child: Text(

"Page",

style: TextStyle(color: Colors.white, fontSize: 22.0),

),

),

);

}

},

itemCount: 10,

)

Here, we transform the page being swiped from and the page being swiped to.

currentPageValue.floor() gives us the page on the left and

currentPageValue.floor() gives us the page on the right

In this example, we rotate the page on the X direction as it is swiped by a value of currentPageValue minus the index in radiants. You can amplify the effect by multiplying this value.

We can tweak this transform and alignment of transform to give us multiple types of new page transitions.

Transition 2

Similar code structure, just with a different transformation:

PageView.builder(

controller: controller,

itemBuilder: (context, position) {

if (position == currentPageValue.floor()) {

return Transform(

transform: Matrix4.identity()..rotateY(currentPageValue - position)..rotateZ(currentPageValue - position),

child: Container(

color: position % 2 == 0 ? Colors.blue : Colors.pink,

child: Center(

child: Text(

"Page",

style: TextStyle(color: Colors.white, fontSize: 22.0),

),

),

),

);

} else if (position == currentPageValue.floor() + 1){

return Transform(

transform: Matrix4.identity()..rotateY(currentPageValue - position)..rotateZ(currentPageValue - position),

child: Container(

color: position % 2 == 0 ? Colors.blue : Colors.pink,

child: Center(

child: Text(

"Page",

style: TextStyle(color: Colors.white, fontSize: 22.0),

),

),

),

);

} else {

return Container(

color: position % 2 == 0 ? Colors.blue : Colors.pink,

child: Center(

child: Text(

"Page",

style: TextStyle(color: Colors.white, fontSize: 22.0),

),

),

);

}

},

itemCount: 10,

)

Here, we rotate around both Y and Z axes.

Transition 3

This is a similar type of transition last time but with a 3-D effect added.

PageView.builder(

controller: controller,

itemBuilder: (context, position) {

if (position == currentPageValue.floor()) {

return Transform(

transform: Matrix4.identity()..setEntry(3, 2, 0.004)..rotateY(currentPageValue - position)..rotateZ(currentPageValue - position),

child: Container(

color: position % 2 == 0 ? Colors.blue : Colors.pink,

child: Center(

child: Text(

"Page",

style: TextStyle(color: Colors.white, fontSize: 22.0),

),

),

),

);

} else if (position == currentPageValue.floor() + 1){

return Transform(

transform: Matrix4.identity()..setEntry(3, 2, 0.004)..rotateY(currentPageValue - position)..rotateZ(currentPageValue - position),

child: Container(

color: position % 2 == 0 ? Colors.blue : Colors.pink,

child: Center(

child: Text(

"Page",

style: TextStyle(color: Colors.white, fontSize: 22.0),

),

),

),

);

} else {

return Container(

color: position % 2 == 0 ? Colors.blue : Colors.pink,

child: Center(

child: Text(

"Page",

style: TextStyle(color: Colors.white, fontSize: 22.0),

),

),

);

}

},

itemCount: 10,

)

The line

..setEntry(3, 2, 0.004)

gives the pages a 3-D like effect.

Transition 4

PageView.builder(

controller: controller,

itemBuilder: (context, position) {

if (position == currentPageValue.floor()) {

return Transform(

alignment: Alignment.center,

transform: Matrix4.identity()..setEntry(3, 2, 0.001)

..rotateX(currentPageValue - position)

..rotateY(currentPageValue - position)

..rotateZ(currentPageValue - position),

child: Container(

color: position % 2 == 0 ? Colors.blue : Colors.pink,

child: Center(

child: Text(

"Page",

style: TextStyle(color: Colors.white, fontSize: 22.0),

),

),

),

);

} else if (position == currentPageValue.floor() + 1){

return Transform(

alignment: Alignment.center,

transform: Matrix4.identity()..setEntry(3, 2, 0.001)

..rotateX(currentPageValue - position)

..rotateY(currentPageValue - position)

..rotateZ(currentPageValue - position),

child: Container(

color: position % 2 == 0 ? Colors.blue : Colors.pink,

child: Center(

child: Text(

"Page",

style: TextStyle(color: Colors.white, fontSize: 22.0),

),

),

),

);

} else {

return Container(

color: position % 2 == 0 ? Colors.blue : Colors.pink,

child: Center(

child: Text(

"Page",

style: TextStyle(color: Colors.white, fontSize: 22.0),

),

),

);

}

},

itemCount: 10,

)

A lot more types can be created by simply changing rotation angles, axes, alignments and translations.

Demo App using PageView

To demonstrate a simple app using PageView in Flutter, I created an example app to study words for the GRE. This app displays and lets the user save the hardest words using SQLite to save them. It also has Text-To-Speech for pronouncing the word itself.

You can find this app here: https://github.com/deven98/FlutterGREWords

That’s it for this article! I hope you enjoyed it, and leave a few claps if you did. Follow me for more Flutter articles and comment for any feedback you might have about this article.

Feel free to check out my other profiles and articles as well:

Some of my other articles