Parallax effect in PageView – UI Tickets Challenge
Parallax effects are awesome. Having elements move in the different speed during scrolling can easily provide the unique feeling for the application and they can make the user think that your app is well-polished. In this post, I will try to achieve parallax effect using PageView, Transforms, Alignments and some basic math. To show you how to do that, I picked the Buy Tickets design from dribbble created by Dldp. Let’s do it! ?
The design
This post focuses only on the slider part of the design. We will cover creating the cards, the slider and then we will move images, texts and buttons inside those cards.
The bottom sheet is coming soon in the next post.?
. . .
Starting point
I don’t want to waste our time on the aspects that don’t really matter, so let’s skip the headers and bottom menu and focus only on the slider. You can always find the full code in here. This is our starting point:
We have used the Placeholder
widget in place of future PageView
and it looks like this:
Starting point
. . .
The slider
Creating the cards
Let’s replace that placeholder with some actual content. We will create a new widget called SlidingCard
which will represent one element in the slider. So far let’s wrap it in SizedBox
. We will introduce PageView
later on. So the _SlidingCardsViewState
now looks like this:
Now, what should SlidingCard
look like? It definitely drops some shadows so we should think of Material
or Card
widget. I went with the Card
. We can see that this card needs to have rounded corners, so will need to specify shape
parameter. We can also notice that the image will cover slightly over half of the image, will add that too. Let’s look at the code:
As said earlier, we used Card
. We have specified the elevation
to 8
to have a bigger shadow. Using RoundedRectangleBorder
as card’s shape let us round down the corners, however, the image displayed on the top wouldn’t respect that and it would have sharp corners sticking out of the card. To avoid that we can use the ClipRRect
widget to simply clip the image to match the card’s shape. At this moment the app looks like this:
Now we can add the content of the card. It is rather simple: a Column
with Text
s and Row
with more Text
s:
The whole card should look like that:
You may notice that the fonts don’t exactly match but let it be our little secret. ?
Creating the PageView
Now when we have the SlidingCard
widget we can focus on the PageView
. Adding a PageView
is very simple. However, in our design you can see more than one card at the time, there is also a small part of the next card. To achieve that, we will use PageController
with viewportFraction
parameter, which determines how much space of the main axis should the one page take. In our case, it will be 80%.
Cards in PageView
. . .
The parallax effect
Images
It’s time for the parallax effect! I want to keep it as simple as possible, so we will avoid adding any complex animations and focus only on what we get from PageController
. And what we get is page
, which gives the information on which page is currently displayed. It is a double and it works like this: 0
means the first page, 1
means the second page and let’s say 0.3
means 30% way between the first and the second page. Having that, we can pass to each card the page - cardIndex
which will basically mean: how far is this card from being displayed.
It’s worth mentioning that the approach with the setState means that everytime pageController emits value, the whole _SlidingCardsViewState will be rebuilt. If you want to make it more efficient, you can wrap every widget that would depend on the pageOffset in AnimatedBuilder. AnimatedBuilder can accept the scrollable (pageController), the child and the builder and it would rebuild only the widgets that need rebuilding. Despite that I will stay with setState to keep the code as simple as possible but remember that this is not the optimal way to do it.
Thanks to Simon Lightfoot for pointing out this issue.
Having the information on “how far is the page from being in the displayed” named as offset
we can have some fun with it. When it comes to images, the easiest way is to change the alignment
of the image. Having alignment depend on the offset, we will make images see move parallel to the movement of the card.
I have used -offset.abs()
to get the look from the design but you can experiment with that value to find the one that suits your app best.
Now we can see that images look like they’re moving in a slightly different speed than the cards:
Parallax images
Texts
Now before we move the texts and buttons, we need to notice that in the design those elements are always moving in the same direction and that they need to come back to their original place after the movement. That means, we cannot use a linear approach towards the offset
– we will use the Gaussian function. For those, who don’t know what it is, let me show you a simple graph illustrating how it looks:
We will use our Gaussian function in a way, that the value will be the biggest when offset
is equal to 0.5 (the top of the bell) and the further from 0.5 Gaussian function will return values closer to 0. Having that, we are going to make use of Transform
widget using simple translation to change widgets’ position based on the Gaussian value and move them right. The code will make it clear:
All we needed to do is wrapping the texts Transform.translate
and now we can see that when user scrolls, those elements tend to move a bit horizontally.
Having all the new translations we can look at the final result:
The design
The result
We have successfully added the parallax effect to our cards using only PageController
, Alignment
and Transform.translate
!
I hope you enjoyed this post, if so please leave the star in the GitHub repo ?
If you have any questions, feel free to leave a comment.
Cheers ?
Marcin Szałek
Founder of Fidev
Flutter enthusiast since Alpha release in 2017. Believes that sharing is caring, which lead him to start a technical blog dedicated fo Flutter in its early days. Loves to see beautiful designs become real apps and is willing to help make it happen. Enjoys sunny beaches far from home.
Join the newsletter!
Join the newsletter to keep track with latest posts and get my special Widget to animate views' entrances without any hassle for FREE!
Check out other posts!
Stripe Checkout in Flutter Web
Flutter Web is getting more mature every day. If you want to accept payments using Stripe Checkout in your Flutter web application, this article is just for you!
Stripe Checkout in mobile Flutter app
Have you ever struggled to integrate card payments into your mobile Flutter app? If so, today is your lucky day! In this post, I present how to use Stripe Checkout in the Flutter app without any hassle!
Interacting with Widgets using Framy
Have you ever developed a widget or a page and you wanted to make sure it works correctly in different scenarios but then it turned out that you can’t just reproduce all the cases you want to cover? Framy may solve such problems!
Another great job❣️❣️??.
Thanks 🙂
Cool! Really Helpful!
🙂
hii nice work men ..i love ur works …
and if its not too much to ask am kinda more interested on bottom to top scrolling part, can you tell how you do that… i was doing something with that too….
thanks anyways
I will cover it in the next post, don’t know how to do it yet 😀
You Are best,
Finished,
Legend
Thanks,
🙂
Congratulations
Thanks 🙂
Great App Marcin! Your apps are really amazing and helpful. Keep sharing!! Well done!
Thanks 🙂
hello dear its the most help full video thank you and can you please show us how to get the functionality of the tab bar
What do you mean exactly?
Hi, I have a question, I would like it when you click on the “reserve” button, browse each card on a different page, what should you do?
Well, obviously it depends on what you need exactly but you can take the card widget and put inside the new page using some new Scaffold and Navigator.of(context).push.
How can we make the tab’s name slide as well?
Currently it is static.
I’m not sure how you expect it to slide 🙁
Hello, can u pls help me. I have draggablescrollableshet, but i would like to use scrollcontroller of that in other widget, which is not child of dragablescrolshet. I planing to moving out widget above draggablescrollableshet when it scroll up.
thx before, im excited to make animation because ur presentation at flutter europe
Good job!!! thanks a lot. Can you please work on a complex UI responsive design?
Nice Design…
Hi, can you explain your calculation gauss value please?