'Animating widgets positions while scrolling
I'm trying to animate widgets in my app depending of the user's scroll and the position inside my scrolling widget (CustomScrollView).
So far i achieved something that looks very nice using the method i'll show below, but i'm afraid that this specific method:
- Is not the most effective in terms of performance and resources.
- Is not the smoothest and result in non-fluid animations.
- Won't be consistent across all sort of devices and resolutions.
Here is what i want to achieve, notice the text's position, and the scrolling page indicator at the bottom-left corner:
I achieved it by doing the following steps:
Creating a function (
_offsetPosition) which gets the current offset, an index of the page which the widget belongs to, the device's view-port dimensions and a coefficient i'm using to speed or slow the animation. The function will return a value between -1.0 and 1.0, while -1.0 is before the page shows up until the very moment it shows on the screen, 1.0 just when it disappears, and 0.0 is exactly when the page fills my view-port.Use that function inside a listener for the
ScrollControllerand changing the value of a variable according to the scroll and other constants i define to make it change according to my needs.Using that variable as
Paddingfor my widget (or for any other parameter,Opacityfor example).
Here is the _offsetPosition function:
double _offsetPosition(double currentOffset, int pageIndex,
double viewportDimension, double coefficient) {
// Returns a value between -1.0 (left edge and before) to 1.0 (right edge and after).
// 1.0 when the page fills the viewport exactly.
// Making sure the return value won't be below -1.0 or 1.0 to avoid errors.
double position = (currentOffset - pageIndex * viewportDimension) *
coefficient /
viewportDimension;
if (position <= -1.0) {
return -1.0;
} else if (position >= 1.0) {
return 1.0;
} else {
return position;
}
}
This is the listener i define inside my initState to change the variables values and build the screen when it changes:
void initState() {
super.initState();
_scrollController.addListener(() {
setState(() {
_pagePosition = _scrollController.offset /
_scrollController.position.viewportDimension;
_bg1Parallax = 0.2 -
_offsetPosition(_scrollController.offset, 0,
_scrollController.position.viewportDimension, 1.0) *
0.4;
_bg2Parallax = 0.2 -
_offsetPosition(_scrollController.offset, 1,
_scrollController.position.viewportDimension, 1.0) *
0.4;
_text1Padding = _offsetPosition(_scrollController.offset, 0,
_scrollController.position.viewportDimension, 1.0) *
1000.0;
_text1Opacity = max(
0.0,
1.0 -
_offsetPosition(_scrollController.offset, 0,
_scrollController.position.viewportDimension, 3.0)
.abs());
});
});
}
And here is an example for the text and icon widgets that moves when the user scrolls, since the value of _pagePosition and _text1Padding grows when the user scrolls forward and vice versa:
Icon widget:
new Padding(
padding:
new EdgeInsets.only(left: _pagePosition * 20.0),
child: new Padding(
padding: new EdgeInsets.all(0.0),
child: new Icon(
FontAwesomeIcons.circle,
size: 15.0,
color: Colors.white,
),
),
)
Text widget:
new Padding(
padding: new EdgeInsets.only(bottom: _text1Padding),
child: new Center(
child: new Opacity(
opacity: _text1Opacity,
child: new Text(
'Text',
style: new TextStyle(
fontSize: 100.0, color: Colors.white),
),
),
),
)
TL;DR
Should i animate a widget's position using a value that changes, according to the ScrollController offset, as a Padding parameter?
Solution 1:[1]
Did you try to run your app in release mode, on a real device?
In general it should not be a problem to rebuild the widget tree when the scroll position changes because Flutter was built to handle this efficiently (the underlying heavy RenderObject tree is not rebuilt).
An alternative approach would be the usage of custom RenderSlivers, as demonstrated in the flutter_gallery example application. You can download the application on Google Play (in the App, select Studies > Animation).
I recorded a video of the animations: https://i.imgur.com/Pj9x09q.mp4

(source: flutter.io)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Glorfindel |

