【问题标题】:Hero animation and scroll to position between two list in Flutter英雄动画和滚动到 Flutter 中两个列表之间的位置
【发布时间】:2021-10-12 09:24:04
【问题描述】:

我将文件显示为缩略图,例如 Instagram 用户的个人资料。

当我点击一个项目(缩略图)时,我必须执行一个Hero 动画来显示全屏页面。

我还想打开全屏页面,整个列表直接从所选帖子的给定索引开始,就像在 Instagram 中一样。

这是一个简短的 GIF,可以更好地表达我的意思:

我尝试了scroll_to_index 包,但这不能满足我的需要(动画坏了而且太慢了)。

请问我怎样才能做到这一点?

【问题讨论】:

    标签: flutter dart flutter-animation flutter-listview


    【解决方案1】:

    将所选项目传递给目标小部件并动态构建Hero标签。

    主要思想是避免匹配的英雄标签过多。

    class MyImagesList extends Stateless Widget {
      final String selectedItem;
    
      final List<String> items;
    
      const MyImagesList(this.selectedItem, this.items);
    
      void build(BuildContext context) {
        return Column(children: [
          for (var item in items)
            item == selectedItem
              ? Hero(tag: item, child: Text(item))
              : Text(item)
         ]);
      }
    }
    

    【讨论】:

      【解决方案2】:

      这就是我所做的,试试:

      import 'package:flutter/material.dart';
      
      import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
      
      void main() => runApp(MyApp());
      
      class MyApp extends StatelessWidget {
        @override
        Widget build(BuildContext context) {
          return MaterialApp(
            debugShowCheckedModeBanner: false,
            home: HomePage(),
          );
        }
      }
      
      class HomePage extends StatefulWidget {
        @override
        _HomePageState createState() => _HomePageState();
      }
      
      class _HomePageState extends State<HomePage> {
        @override
        void initState() {
          super.initState();
        }
      
        @override
        void dispose() {
          super.dispose();
        }
      
        @override
        Widget build(BuildContext context) {
          return Scaffold(
            body: GridView.count(
              crossAxisCount: 3,
              children: List.generate(99, (index) {
                return Container(
                  width: double.infinity,
                  height: double.infinity,
                  child: GestureDetector(
                    onTap: () {
                      Navigator.push(
                        context,
                        MaterialPageRoute(
                            builder: (context) => ListPage(index: index)),
                      );
                    },
                    child: Hero(
                      tag: 'photo$index',
                      child: Image.network(
                        'https://images.unsplash.com/photo-1628701621033-50564c683bb0?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=80',
                        fit: BoxFit.cover,
                      ),
                    ),
                  ),
                );
              }),
            ),
          );
        }
      }
      
      class ListPage extends StatefulWidget {
        final int index;
      
        ListPage({Key key, @required this.index}) : super(key: key);
      
        @override
        _ListPageState createState() => _ListPageState();
      }
      
      class _ListPageState extends State<ListPage> {
        final ItemScrollController itemScrollController = ItemScrollController();
        final ItemPositionsListener itemPositionsListener =
            ItemPositionsListener.create();
      
        @override
        void initState() {
          super.initState();
        }
      
        @override
        void dispose() {
          super.dispose();
        }
      
        @override
        Widget build(BuildContext context) {
          return ScrollablePositionedList.builder(
            initialScrollIndex: widget.index,
            itemCount: 99,
            itemBuilder: (context, index) {
              return Column(
                children: [
                  AspectRatio(
                    aspectRatio: 1,
                    child: Hero(
                      tag: 'photo$index',
                      child: Image.network(
                        'https://images.unsplash.com/photo-1628701621033-50564c683bb0?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=80',
                        fit: BoxFit.cover,
                      ),
                    ),
                  ),
                  Container(
                    height: 50,
                    width: MediaQuery.of(context).size.width,
                    child: Text('$index'),
                  ),
                ],
              );
            },
            itemScrollController: itemScrollController,
            itemPositionsListener: itemPositionsListener,
          );
        }
      }
      

      【讨论】:

      • 感谢您的回答,但您使用的包不是空安全的。我没有在我的问题中指定它我的坏。我希望该逻辑实际上可以与任何可滚动列表一起使用,但是如果您有一个有效的空安全示例,我将立即尝试!
      • 它工作得很好,谢谢。我与SmartRefresher 包发生冲突,以防其他人面临ScrollablePositionedList 的奇怪滚动问题(尽管有初始索引,它仍滚动到底部,这就是为什么我花了这么长时间来验证。
      • 很高兴有帮助,TGIF!
      猜你喜欢
      • 1970-01-01
      • 2019-09-28
      • 2018-11-01
      • 1970-01-01
      • 2021-11-13
      • 1970-01-01
      • 2021-10-16
      • 2020-05-15
      • 2017-11-08
      相关资源
      最近更新 更多