Lao Meng's guide: This article is the fourth in the Flutter animation series. This article introduces animation sequences, sharing animations, and routing animations.
Animation sequence
The combined animation is used in Flutter Interval
, Interval
inherited from it Curve
, and the usage is as follows:
Animation _sizeAnimation = Tween(begin: 100.0, end: 300.0).animate(CurvedAnimation(
parent: _animationController, curve: Interval(0.5, 1.0)));
Indicates that the _sizeAnimation
animation starts from 0.5 (half) to the end. If the animation duration is 6 seconds, _sizeAnimation
it starts from the third second.
Interval
In begin
and end
the SP value is 0.0 to 1.0.
The following is to implement a color change first and then a size change. The code is as follows:
class AnimationDemo extends StatefulWidget {
@override
State<StatefulWidget> createState() => _AnimationDemo();
}
class _AnimationDemo extends State<AnimationDemo>
with SingleTickerProviderStateMixin {
AnimationController _animationController;
Animation _colorAnimation;
Animation _sizeAnimation;
@override
void initState() {
_animationController =
AnimationController(duration: Duration(seconds: 5), vsync: this)
..addListener((){setState(() {
});});
_colorAnimation = ColorTween(begin: Colors.red, end: Colors.blue).animate(
CurvedAnimation(
parent: _animationController, curve: Interval(0.0, 0.5)));
_sizeAnimation = Tween(begin: 100.0, end: 300.0).animate(CurvedAnimation(
parent: _animationController, curve: Interval(0.5, 1.0)));
//开始动画
_animationController.forward();
super.initState();
}
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Container(
height: _sizeAnimation.value,
width: _sizeAnimation.value,
color: _colorAnimation.value),
],
),
);
}
@override
void dispose() {
_animationController.dispose();
super.dispose();
}
}
The effect is as follows:
We can also set up simultaneous animation, just change Interval
the values of both Interval(0.0, 1.0)
.
Imagine the following scene, a red box, the animation duration is 6 seconds, the first 40% of the time is from 100->200, then 200 is unchanged for 20% of the time, and the last 40% of the time is from 200->300. This effect is achieved by TweenSequence, the code is as follows:
_animation = TweenSequence([
TweenSequenceItem(
tween: Tween(begin: 100.0, end: 200.0)
.chain(CurveTween(curve: Curves.easeIn)),
weight: 40),
TweenSequenceItem(tween: ConstantTween<double>(200.0), weight: 20),
TweenSequenceItem(tween: Tween(begin: 200.0, end: 300.0), weight: 40),
]).animate(_animationController);
weight
Indicates the weight of each Tween.
The final effect is as follows:
Share animation
Hero is our commonly used transition animation. When the user clicks on a picture and switches to another page, this page also has this picture. Then it is appropriate to use the Hero component. Let’s take a look at the rendering of Hero:
The code of the list page achieved by the above effect is as follows:
class HeroDemo extends StatefulWidget {
@override
State<StatefulWidget> createState() => _HeroDemo();
}
class _HeroDemo extends State<HeroDemo> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: GridView(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3, crossAxisSpacing: 5, mainAxisSpacing: 3),
children: List.generate(10, (index) {
if (index == 6) {
return InkWell(
onTap: () {
Navigator.push(
context,
new MaterialPageRoute(
builder: (context) => new _Hero1Demo()));
},
child: Hero(
tag: 'hero',
child: Container(
child: Image.asset(
'images/bird.png',
fit: BoxFit.fitWidth,
),
),
),
);
}
return Container(
color: Colors.red,
);
}),
),
);
}
}
The second page code is as follows:
class _Hero1Demo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Container(
alignment: Alignment.topCenter,
child: Hero(
tag: 'hero',
child: Container(
child: Image.asset(
'images/bird.png',
),
),
)),
);
}
}
Both pages have Hero controls, and the tag
parameters are the same.
Routing animation
Transition is to jump from the current page to another page. The jump page is jumped to the new page through the Navigator in Flutter as follows:
Navigator.push(context, MaterialPageRoute(builder: (context) {
return _TwoPage();
}));
Go back to the previous page:
Navigator.pop(context);
Flutter provides two transition animations, namely MaterialPageRoute and CupertinoPageRoute . MaterialPageRoute displays different effects according to different platforms. The Android effect is from bottom to top, and the iOS effect is from left to right. CupertinoPageRoute is from left to right regardless of platform.
Examples of using MaterialPageRoute are as follows:
class NavigationAnimation extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Center(
child: OutlineButton(
child: Text('跳转'),
onPressed: () {
Navigator.push(context, CupertinoPageRoute(builder: (context) {
return _TwoPage();
}));
},
),
),
);
}
}
class _TwoPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Container(
color: Colors.blue,
),
);
}
}
iOS effect:
What if I want to customize the transition animation?
Customizing any component is the same. If the system is similar, just look at how the source code is implemented, and then customize the component according to its template.
Back to the topic, look at the inheritance relationship of MaterialPageRoute:
PageRoute's inheritance relationship:
MaterialPageRoute and CupertinoPageRoute both inherit from PageRoute, so the focus is on PageRoute. PageRoute is an abstract class, and its subclass also has a PageRouteBuilder. By looking at its name, you know that this is a custom animation effect. PageRouteBuilder source code:
pageBuilder
Indicates the page to jump to.
transitionsBuilder
Indicates the animation effect of the page, the default value code:
Widget _defaultTransitionsBuilder(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget child) {
return child;
}
Found through the source code, there is no animation effect by default.
The custom transition animation only needs to transitionsBuilder
be modified :
Navigator.push(
context,
PageRouteBuilder(pageBuilder: (
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
) {
return _TwoPage();
}, transitionsBuilder: (BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child) {
return SlideTransition(
position: Tween(begin: Offset(-1, 0), end: Offset(0, 0))
.animate(animation),
child: child,
);
}));
Encapsulate it for easy use:
class LeftToRightPageRoute extends PageRouteBuilder {
final Widget newPage;
LeftToRightPageRoute(this.newPage)
: super(
pageBuilder: (
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
) =>
newPage,
transitionsBuilder: (
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child,
) =>
SlideTransition(
position: Tween(begin: Offset(-1, 0), end: Offset(0, 0))
.animate(animation),
child: child,
),
);
}
use:
Navigator.push(context, LeftToRightPageRoute(_TwoPage()));
Not only these panning paintings, but also the animations such as rotation and zooming that you learned before can directly replace SlideTransition.
The above animation only animates the new page. If you want to achieve the effect of the current page being ejected from the top by the new page, the implementation is as follows:
class CustomPageRoute extends PageRouteBuilder {
final Widget currentPage;
final Widget newPage;
CustomPageRoute(this.currentPage, this.newPage)
: super(
pageBuilder: (
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
) =>
currentPage,
transitionsBuilder: (
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child,
) =>
Stack(
children: <Widget>[
SlideTransition(
position: new Tween<Offset>(
begin: const Offset(0, 0),
end: const Offset(0, -1),
).animate(animation),
child: currentPage,
),
SlideTransition(
position: new Tween<Offset>(
begin: const Offset(0, 1),
end: Offset(0, 0),
).animate(animation),
child: newPage,
)
],
),
);
}
The essence is to animate two pages, using:
Navigator.push(context, CustomPageRoute(this, _TwoPage()));
In addition to custom routing animations, at the Flutter 1.17 release conference, the Flutter team also released a new Animations package, which provides pre-built animations that implement the new Material motion specifications.
It provides a series of animations, some effects:
Details: https://juejin.im/post/6847902223909781511
communicate with
Laomeng Flutter blog address (330 control usage): http://laomengit.com
Welcome to join the Flutter exchange group (WeChat: laomengit) and follow the public account [Lao Meng Flutter]: