Bringing the PageTransformer to Flutter
Coming from a native Android developer background, I was ecstatic when the design support library came out. A lot of design guidelines and patterns existed, but there wasn’t officially supported libraries to implement them. One of those patterns was ViewPager, a component that has swipe gestures to flip through pages of data.
How the sample app for this article looks like.
ViewPager was already great, but when PageTransformer was introduced, the whole thing went to another level. Now we could create nice parallax scroll effects easily. PageTransformer
spurred up nice looking app onboarding experiences, and they aren’t going away anytime soon.
PageViews and PageTransformers in Flutter
Flutter’s equivalent of ViewPagers
is the PageView widget. The API is much simpler: we don’t have to provide any separate adapters to have a few pages. When having a huge (or indefinite) amount of pages, the API is still a lot easier than its Android counterpart.
One thing that seems to be missing is the PageTransformer
. I needed a way to make some fancy effects but couldn’t find anything. I ended up implementing a PageTransformer
class myself.
Here’s the API I came up with.
import 'page_transformer.dart';
class Example extends StatelessWidget {
@override
Widget build(BuildContext context) {
return PageTransformer(
pageViewBuilder: (context, pageVisibilityResolver) {
return PageView.builder(
itemBuilder: (context, index) {
final pageVisibility =
pageVisibilityResolver.resolvePageVisibility(index);
// Use these two properties to transform your "Hello World" text widget!
// In this example, the text widget fades in and out of view, since we use
// the visibleFraction property, which can be between 0.0 - 1.0.
final position = pageVisibility.pagePosition;
final visibleFraction = pageVisibility.visibleFraction;
return Opacity(
opacity: visibleFraction,
child: Text('Hello World!'),
);
},
);
},
);
}
}
I iterated a couple times until I had together what I believe is the simplest possible API. It also supports the new PageView(children: [...])
approach, and I believe, with small modifications, could support scroll effects on ListViews
as well.
The PageTransformer source code
See the finished PageTransformer class here. I commented some key parts, and a high-level description is below.
Here’s the general way it works:
- We wrap the
PageView
inside thePageTransformer
widget’sPageViewBuilder
method. ThePageTransformer
then watches thePageView's
scroll events by wrapping it inside a NotificationListener. - Once a new scroll event happens, the
_PageTransformerState
is then updated with a newPageVisibilityResolver
, with the currentScrollMetrics
provided in its constructor. Once the state is updated, thepageViewBuilder
method gets called with the newly updatedPageVisibilityResolver
. - Inside our
itemBuilder
, we callPageVisibilityResolver#resolvePageVisibility(index)
and pass theindex
of the widget we’re currently building. We get aPageVisibility
object which contains useful information about the current page’s position and what portion of it is currently visible. - We can transform our pages using the information provided by the
PageVisibility
object.
The sample app
The sample app, showcasing some cool parallax effects, can be found here.
Conclusion
I don’t really know that deeply about Flutter’s widget rebuilding logic to tell if this is the most efficient way to do it. However, I believe it’s a viable and nice way of doing various effects in a PageView
until something official comes up. At least I got buttery smooth animations and framerates even on “slow mode”.
Since the pagePosition
here is the same thing as position
in PageTransfomer
on Android, there are lots of tutorials and examples for cool transformations and they’ll work in the same way.
4 comments
likes