【问题标题】:How to create a hero style animation on the same screen route with Flutter?如何用 Flutter 在同屏路线上制作英雄风格的动画?
【发布时间】:2018-09-25 09:02:01
【问题描述】:

我正在尝试创建上面模型中描述的动态动画。我需要的是:

  • 代表头像的圆形(例如用户图片);
  • 下方居中的文本。
  • 在那些(使用一半屏幕)下方是可滚动的PageView

动画应该如下:

开始:Stack中,两者都以开始为中心。
动画:缩小和滑动文本(可变长度) 必须在头像的右侧。
结束:
作为样机中的第二张图片。一边到一边,而下面的内容不断滚动。

SliverPersistentHeader 中考虑与CustomMultiChildLayout 结合,但问题是文本开始居中并结束对齐到左侧,我可以动态地制作动画。最后我试图删除居中文本的偏移量,但感觉不对。

任何帮助或仅与此动画有关的示例将不胜感激。谢谢你。

【问题讨论】:

    标签: animation dart flutter flutter-layout


    【解决方案1】:

    您将需要一个 Sliver 来根据滚动偏移量为您的布局设置动画。更具体地说,SliverPersistentHeader 在您的情况下。

    CustomMultiChildLayout 不是必需的,您可以使用补间和对齐/填充/填充来获得相同的结果。但是,如果您的布局开始变得过于复杂,您可以试一试。

    诀窍是使用 SliverPersistentHeader 给出的滚动偏移量来计算当前进度。然后使用该进程将元素定位在其原始位置和最终位置之间。

    这是一个原始示例:

    class TransitionAppBar extends StatelessWidget {
      final Widget avatar;
      final Widget title;
    
      const TransitionAppBar({this.avatar, this.title, Key key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return SliverPersistentHeader(
          pinned: true,
          delegate: _TransitionAppBarDelegate(
            avatar: avatar,
            title: title,
          ),
        );
      }
    }
    
    class _TransitionAppBarDelegate extends SliverPersistentHeaderDelegate {
      final _avatarTween =
          SizeTween(begin: Size(150.0, 150.0), end: Size(50.0, 50.0));
      final _avatarMarginTween =
          EdgeInsetsTween(begin: EdgeInsets.zero, end: EdgeInsets.only(left: 10.0));
      final _avatarAlignTween =
          AlignmentTween(begin: Alignment.topCenter, end: Alignment.centerLeft);
    
      final _titleMarginTween = EdgeInsetsTween(
          begin: EdgeInsets.only(top: 150.0 + 5.0),
          end: EdgeInsets.only(left: 10.0 + 50.0 + 5.0));
      final _titleAlignTween =
          AlignmentTween(begin: Alignment.center, end: Alignment.centerLeft);
    
      final Widget avatar;
      final Widget title;
    
      _TransitionAppBarDelegate({this.avatar, this.title})
          : assert(avatar != null),
            assert(title != null);
    
      @override
      Widget build(
          BuildContext context, double shrinkOffset, bool overlapsContent) {
        final progress = shrinkOffset / 200.0;
    
        final avatarSize = _avatarTween.lerp(progress);
        final avatarMargin = _avatarMarginTween.lerp(progress);
        final avatarAlign = _avatarAlignTween.lerp(progress);
    
        final titleMargin = _titleMarginTween.lerp(progress);
        final titleAlign = _titleAlignTween.lerp(progress);
        return Stack(
          fit: StackFit.expand,
          children: <Widget>[
            Padding(
              padding: avatarMargin,
              child: Align(
                alignment: avatarAlign,
                child: SizedBox.fromSize(size: avatarSize, child: avatar),
              ),
            ),
            Padding(
              padding: titleMargin,
              child: Align(
                alignment: titleAlign,
                child: DefaultTextStyle(
                    style: Theme.of(context).textTheme.title, child: title),
              ),
            )
          ],
        );
      }
    
      @override
      double get maxExtent => 200.0;
    
      @override
      double get minExtent => 100.0;
    
      @override
      bool shouldRebuild(_TransitionAppBarDelegate oldDelegate) {
        return avatar != oldDelegate.avatar || title != oldDelegate.title;
      }
    }
    

    您可以将其与 CustomScrollView 一起使用:

    Scaffold(
      body: CustomScrollView(
        slivers: <Widget>[
          TransitionAppBar(
            avatar: Material(
              color: Colors.blue,
              elevation: 3.0,
            ),
            title: Text("Hello World"),
          ),
          SliverList(
            delegate: SliverChildBuilderDelegate((context, index) {
              return ListTile(
                title: Text('$index'),
              );
            }),
          )
        ],
      ),
    );
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-11-01
      • 2021-06-23
      • 1970-01-01
      • 1970-01-01
      • 2018-08-31
      • 2020-04-23
      • 2020-03-03
      • 2020-05-15
      相关资源
      最近更新 更多