动画Animation开发指南-Hero动画2

33 篇文章 2 订阅

一、Hero函数原型

-tag:[必须]用于关联两个Hero动画的标识

-createRectTween:定义目标Hero的边界,在从起始位置到目的位置的“飞行”过程中该如何变化

-child:[必须]定义动画所呈现的widget

 

实现径向hero动画

 

二、实现径向动画

从圆形变方形,从方形变圆形

import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart' show timeDilation;
import 'dart:math' as math;
void main() => runApp(MaterialApp(home: RadialExpansionDemo()));

class Photo extends StatelessWidget{
  final String photo;
  final VoidCallback onTap;
  final double width;

  const Photo({Key key, this.photo, this.onTap, this.width}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Material(
      color: Theme.of(context).primaryColor.withOpacity(0.25),
      child: InkWell(
        onTap: onTap,
        child: LayoutBuilder(builder: (context,size){
          return Image.network(photo,fit: BoxFit.contain);
        }),
      ),
    );
  }
}

class RadialExpansionDemo extends StatelessWidget{
  static const double kMinRadius=32.0;
  static const double kMaxRadius=128.0;
  static const opacityCurve= const Interval(0.0,0.75, curve : Curves.fastOutSlowIn);

  static RectTween _createRectTween(Rect begin,Rect end){
    return MaterialRectArcTween(begin: begin,end: end);
  }

  static Widget _buildPage(BuildContext context,String imageName,String description){
    return Container(
      color: Theme.of(context).canvasColor,
      child: Center(
        child: Card(
          elevation: 8,
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: <Widget>[
              SizedBox(
                width: kMaxRadius*2,
                height: kMaxRadius*2,
                child: Hero(
                    createRectTween: _createRectTween,
                    tag: imageName, child: RadialExpansion(
                  maxRadius: kMaxRadius,
                  child: Photo(
                    photo: imageName,
                    onTap: (){
                      Navigator.of(context).pop();
                    },
                  ),
                )
                ),
              ),
              Text(description,style: TextStyle(fontWeight: FontWeight.bold),textScaleFactor: 3.0),
              const SizedBox(height: 16)
            ],
          ),
        ),
      ),
    );
  }

  Widget _buildHero(BuildContext context,String imageName,String description){
    return Container(
      width: kMinRadius*2,
      height: kMinRadius*2,
      child: Hero(
        createRectTween: _createRectTween,
          tag: imageName,
          child: RadialExpansion(
            maxRadius: kMaxRadius,
            child: Photo(
              photo: imageName,
              onTap: (){
                Navigator.of(context).push(
                    PageRouteBuilder<void>(
                      pageBuilder: (BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation){
                          return AnimatedBuilder(animation: animation, builder: (context,child){
                            return Opacity(opacity:
                              opacityCurve.transform(animation.value),
                              child: _buildPage(context, imageName, description),
                            );
                          });
                        }
                    )
                    );
              }
            ),
            ),
          )
      );

  }

  @override
  Widget build(BuildContext context) {
    timeDilation=5.0;
    return Scaffold(
      appBar: AppBar(
        title: const Text('Radial Transition Demo'),
      ),
      body:Container(
        padding: EdgeInsets.all(32),
        alignment: FractionalOffset.bottomLeft,
        child: Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: <Widget>[
            _buildHero(context, 'https://raw.githubusercontent.com/flutter/website/master/examples/_animation/radial_hero_animation/images/chair-alpha.png', "Chair"),
            _buildHero(context, 'https://raw.githubusercontent.com/flutter/website/master/examples/_animation/radial_hero_animation/images/binocular-alpha.png', "Binoculars"),
            _buildHero(context, 'https://raw.githubusercontent.com/flutter/website/master/examples/_animation/radial_hero_animation/images/beachball-alpha.png', "Beach ball"),
          ],
        ),
      ) ,
    );
  }

}

class RadialExpansion extends StatelessWidget{

  final double maxRadius;
  final clipRectSize;
  final Widget child;

  const RadialExpansion({
    Key key,
    this.maxRadius,
    this.child})
      :clipRectSize=2.0*(maxRadius/math.sqrt2), super(key: key);
  @override
  Widget build(BuildContext context) {
    return ClipOval(
      child: Center(
        child: SizedBox(
          width: clipRectSize,
          height: clipRectSize,
          child: ClipRect(
            child: child,
          ),
        ),
      ),
    );
  }


}

class HeroAnimation extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    timeDilation=10.0;
    return Scaffold(
      appBar: AppBar(
        title: const Text('Basic Hero Animation'),
      ),
      body:Center(
        child: Photo(
          photo: 'https://raw.githubusercontent.com/flutter/website/master/examples/_animation/hero_animation/images/flippers-alpha.png',
          width: 300.0,
          onTap: (){
            Navigator.of(context).push(MaterialPageRoute(builder: (context){
              return Scaffold(
                appBar: AppBar(
                  title: const Text('Basic Hero Animation'),
                ),
                body: Container(
                  color:  Colors.lightBlueAccent,
                  padding: EdgeInsets.all(16),
                  alignment: Alignment.topLeft,
                  child: Photo(
                    photo: 'https://raw.githubusercontent.com/flutter/website/master/examples/_animation/hero_animation/images/flippers-alpha.png',
                    width: 100,
                    onTap: (){
                      Navigator.of(context).pop();//关闭当前界面
                    },
                  ),
                ),
              );
            }));
          },
        ),
      ) ,
    );
  }

}



 

运行结果:

 

 

 

 

 

三、实现原理:

1、main函数中使用了StatelessWidget ,

 

2、

定义了两个不同大小的圆形的半径 kMinRadius、kMaxRadius

设置了opacityCurve,值为0~0.75

 

3、

在buildpage方法中定义了一个hero,createRectTween使用的是刚刚创建的_createRectTween

createRectTween用来描述两个动画执行过程中过渡的一个动画效果

这里由圆形径向变化到一个方形,由方形径向变化到圆形

 

4、createRectTween:

_createRectTween用到了MaterialRectCenterArcTween,它是flutter里面的一个类,它就是用于完成从方形到圆形变化的一个辅助类

Tag:关联两个图片之间的tag

 

 

当点击里面的页面的时候,通过pop关闭界面

 

5、创建界面底部三个图形,并通过buildHero生成hero

 

当点击底部图片的时候push了一个新的页面

这里用到了PageRouteBuilder,它用于生成一次性的路由,也就是说可以通过push()跳转到其它界面,然后再通过pop()方法返回当前界面,在界面跳转的时候定义了两个界面的过程

 

在过渡过程中,当前界面会淡入淡出,淡入淡出的效果是通过PageRouteBuilder这个效果实现的。它里面有Animation的回调,通过animation回调改变当前界面的alpha值。

里面调用_buildPage(), _buildPage()里面包了Hero()。

对比标准的Hero动画,这个动画就是多了一个createRectTween这样参数,也就是定义了两个动画在过渡过程中形状变化的效果。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值