最近比较忙,很少发文章了。今天抽空把Hero的转场组件共享说一下
顺便发个转场的动画福利类,可以定义转场的时间,曲线,别客气,随便拿去用。
废话不多说,先看图:
1.透明:
FadeRouter
2.缩放:
ScaleRouter
3.旋转:
RotateRouter
4.透明+缩放+旋转
5.右--->左:
Right2LeftRouter
6.左--->右:
Left2RightRouter
7.上--->下:
Top2BottomRouter
8.下--->上:
Bottom2TopRouter
Hero元素共享
也许上面吸引你的不是界面跳转的动画,而是那个头像神奇般的轨迹。下面就来说一下如何实现。
起始页:OriginPage
class OriginPage extends StatelessWidget { @override Widget build(BuildContext context) { var hero= Hero(//----定义一个Hero,并添加tag标签,此中组件共享 tag: 'user-head', child: ClipRRect( borderRadius: BorderRadius.all(Radius.circular(30)), child: Image.asset( "images/mani.jpg",width: 60,height: 60,fit: BoxFit.cover, ), ), ); var container= Container(//容器,没啥好说的 alignment: Alignment(-0.8, -0.8), child: hero, width: 250, height: 250*0.618, decoration: BoxDecoration(//添加渐变色 gradient: LinearGradient(colors: [Colors.red.withAlpha(99),Colors.yellow.withAlpha(189),Colors.green.withAlpha(88),Colors.blue.withAlpha(230)]) ),); return Scaffold( body: Center(//点击跳转 child: GestureDetector(child: Card(elevation:5,child:container ,),onTap: (){ _toNext(context); },), ), ); } void _toNext(context) {//跳转路由 Navigator.push( context, // FadeRouter(child:TargetPage()), // ScaleRouter(child:TargetPage()), // RotateRouter(child:TargetPage()), // ScaleFadeRotateRouter(child:TargetPage()), // Right2LeftRouter(child:TargetPage()), // Left2RightRouter(child:TargetPage()), // Top2BottomRouter(child:TargetPage()), Bottom2TopRouter(child:TargetPage()),//跳转+动画 ); } } 复制代码
目标页:TargetPage
class TargetPage extends StatelessWidget { @override Widget build(BuildContext context) { var hero=Hero(//----定义一个Hero,为其添加标签,两个标签相同,则可以共享 tag: 'user-head', child: Padding( padding: EdgeInsets.all(16.0), child: CircleAvatar( backgroundColor: Colors.transparent, radius: 72.0, backgroundImage: AssetImage( "images/mani.jpg", ), ), ), ); var touch=InkWell(onTap: (){ Navigator.of(context).pop(); },child: hero,); return Scaffold( appBar: AppBar(leading:touch ,), body: Container( decoration: BoxDecoration( gradient: LinearGradient(colors: [Colors.red.withAlpha(99),Colors.yellow.withAlpha(189),Colors.green.withAlpha(88),Colors.blue.withAlpha(230)]) ), ), ); } } 复制代码
关于createRectTween属性
在回调中会给两个初始和结束的两个矩形,可以进行矩形动画来控制共享组件的区域,如下图在目标页:
var height=MediaQuery.of(context).size.height; var width=MediaQuery.of(context).size.width; var size=min(height,width); var hero=Hero(//----定义一个Hero,为其添加标签,两个标签相同,则可以共享 createRectTween: ((r1,r2){ return RectTween(begin: Rect.fromLTWH(size/2,0, size, size),end: r2); }), 复制代码
另外还有个要点:同一页面不能出现多处同名Hero
福利时间:路由动画工具
使用方法看上面的路由跳转处,当然你也可以根据下面的定制更酷炫的跳转效果。
import 'package:flutter/cupertino.dart'; //缩放路由动画 class ScaleRouter<T> extends PageRouteBuilder<T> { final Widget child; final int duration_ms; final Curve curve; ScaleRouter({this.child, this.duration_ms = 500,this.curve=Curves.fastOutSlowIn}) : super( pageBuilder: (context, animation, secondaryAnimation) => child, transitionDuration: Duration(milliseconds: duration_ms), transitionsBuilder: (context, a1, a2, child) => ScaleTransition( scale: Tween(begin: 0.0, end: 1.0).animate( CurvedAnimation(parent: a1, curve: curve)), child: child, ), ); } //渐变透明路由动画 class FadeRouter<T> extends PageRouteBuilder<T> { final Widget child; final int duration_ms; final Curve curve; FadeRouter({this.child, this.duration_ms = 500,this.curve=Curves.fastOutSlowIn}) : super( pageBuilder: (context, animation, secondaryAnimation) => child, transitionDuration: Duration(milliseconds: duration_ms), transitionsBuilder: (context, a1, a2, child) => FadeTransition( opacity: Tween(begin: 0.1, end: 1.0).animate( CurvedAnimation(parent: a1, curve:curve,)), child: child, )); } //旋转路由动画 class RotateRouter<T> extends PageRouteBuilder<T> { final Widget child; final int duration_ms; final Curve curve; RotateRouter({this.child, this.duration_ms = 500,this.curve=Curves.fastOutSlowIn}) : super( pageBuilder: (context, animation, secondaryAnimation) => child, transitionDuration: Duration(milliseconds: duration_ms), transitionsBuilder: (context, a1, a2, child) => RotationTransition( turns: Tween(begin: 0.1, end: 1.0).animate( CurvedAnimation(parent: a1, curve:curve,)), child: child, )); } //右--->左 class Right2LeftRouter<T> extends PageRouteBuilder<T> { final Widget child; final int duration_ms; final Curve curve; Right2LeftRouter({this.child,this.duration_ms=500,this.curve=Curves.fastOutSlowIn}) :super( transitionDuration:Duration(milliseconds: duration_ms), pageBuilder:(ctx,a1,a2){return child;}, transitionsBuilder:(ctx,a1,a2,Widget child,) { return SlideTransition( position: Tween<Offset>( begin: Offset(1.0, 0.0), end: Offset(0.0, 0.0),).animate( CurvedAnimation(parent: a1, curve: curve)), child: child ); }); } //左--->右 class Left2RightRouter<T> extends PageRouteBuilder<T> { final Widget child; final int duration_ms; final Curve curve; List<int> mapper; Left2RightRouter({this.child,this.duration_ms=500,this.curve=Curves.fastOutSlowIn}) :assert(true),super( transitionDuration:Duration(milliseconds: duration_ms), pageBuilder:(ctx,a1,a2){return child;}, transitionsBuilder:(ctx,a1,a2,Widget child,) { return SlideTransition( position: Tween<Offset>( begin: Offset(-1.0, 0.0), end: Offset(0.0, 0.0),).animate( CurvedAnimation(parent: a1, curve: curve)), child: child ); }); } //上--->下 class Top2BottomRouter<T> extends PageRouteBuilder<T> { final Widget child; final int duration_ms; final Curve curve; Top2BottomRouter({this.child,this.duration_ms=500,this.curve=Curves.fastOutSlowIn}) :super( transitionDuration:Duration(milliseconds: duration_ms), pageBuilder:(ctx,a1,a2){return child;}, transitionsBuilder:(ctx,a1,a2,Widget child,) { return SlideTransition( position: Tween<Offset>( begin: Offset(0.0,-1.0), end: Offset(0.0, 0.0),).animate( CurvedAnimation(parent: a1, curve: curve)), child: child ); }); } //下--->上 class Bottom2TopRouter<T> extends PageRouteBuilder<T> { final Widget child; final int duration_ms; final Curve curve; Bottom2TopRouter({this.child,this.duration_ms=500,this.curve=Curves.fastOutSlowIn}) :super( transitionDuration:Duration(milliseconds: duration_ms), pageBuilder:(ctx,a1,a2){return child;}, transitionsBuilder:(ctx,a1,a2,Widget child,) { return SlideTransition( position: Tween<Offset>( begin: Offset(0.0, 1.0), end: Offset(0.0, 0.0),).animate( CurvedAnimation(parent: a1, curve: curve)), child: child ); }); } //缩放+透明+旋转路由动画 class ScaleFadeRotateRouter<T> extends PageRouteBuilder<T> { final Widget child; final int duration_ms; final Curve curve; ScaleFadeRotateRouter({this.child, this.duration_ms = 500,this.curve=Curves.fastOutSlowIn}) : super( transitionDuration: Duration(milliseconds: duration_ms), pageBuilder: (ctx, a1, a2)=>child,//页面 transitionsBuilder: (ctx, a1, a2, Widget child,) {//构建动画 return RotationTransition(//旋转动画 turns: Tween(begin: 0.0, end: 1.0).animate(CurvedAnimation( parent: a1, curve: curve, )), child: ScaleTransition(//缩放动画 scale: Tween(begin: 0.0, end: 1.0).animate( CurvedAnimation(parent: a1, curve: curve)), child: FadeTransition(opacity://透明度动画 Tween(begin: 0.5, end: 1.0).animate(CurvedAnimation(parent: a1, curve: curve)), child: child,), ), ); }); } //无动画 class NoAnimRouter<T> extends PageRouteBuilder<T> { final Widget page; NoAnimRouter(this.page) : super( opaque: false, pageBuilder: (context, animation, secondaryAnimation) => page, transitionDuration: Duration(milliseconds: 0), transitionsBuilder: (context, animation, secondaryAnimation, child) => child); } 复制代码
结语
本文到此接近尾声了,如果想快速尝鲜Flutter,《Flutter七日》会是你的必备佳品;如果想细细探究它,那就跟随我的脚步,完成一次Flutter之旅。