【问题标题】:AnimatedSwitcher with IndexedStack带有 IndexedStack 的 AnimatedSwitcher
【发布时间】:2020-01-01 18:57:58
【问题描述】:

我必须使用 IndexedStack 来维护我的 BottomNavigationBar 小部件的状态。 现在我想在切换标签时使用 AnimatedSwitcher(或替代方法)来创建动画。 我在让 AnimatedSwitcher 在更改 IndexedStack 时触发问题。我将 IndexedStack 作为 AnimatedSwitcher 的子级,这显然会导致 AnimatedSwitcher 不触发,因为 IndexedStack 小部件不会改变,只是它的子级。

body: AnimatedSwitcher(  
  duration: Duration(milliseconds: 200),  
  child: IndexedStack(  
    children: _tabs.map((t) => t.widget).toList(),  
    index: _currentIndex,  
  ),  
)

有没有办法解决这个问题?通过手动触发 AnimatedSwitcher,还是使用不同的方法来创建动画? 我也尝试更改密钥,但这显然导致每次创建新状态时它都会创建一个新的 IndexedStack,因此选项卡的状态也会丢失。

【问题讨论】:

    标签: flutter flutter-layout flutter-animation


    【解决方案1】:

    PageTransitionSwitcher( 持续时间:持续时间(毫秒:250), transitionBuilder: (widget, anim1, anim2) {

        return FadeScaleTransition(
          animation: anim1,
          child: widget,
        );
      },
      child: IndexedStack(
        index: _currentIndex,
        key: ValueKey<int>(_currentIndex),
        children: [
          Page1(),
          Page2(),
          Page3()
        ],
      ),
     
    );
    

    【讨论】:

      【解决方案2】:

      尝试将键添加到您的 IndexedStack 和一个 transitionBuilder 方法到您的 AnimatedSwitcher 小部件,如下所示...

      AnimatedSwitcher(
                  duration: Duration(milliseconds: 1200),
                  transitionBuilder: (child, animation) => SizeTransition(
                    sizeFactor: animation,
                    child: IndexedStack(
                      key: ValueKey<int>(navigationIndex.state),
                      index: navigationIndex.state,
                      children: _tabs.map((t) => t.widget).toList(),  
                    ),
                  ),
                  child: IndexedStack(
                    key: ValueKey<int>(navigationIndex.state), //using StateProvider<int>
                    index: navigationIndex.state,
                    children: _tabs.map((t) => t.widget).toList(),  
                  ),
                ),
      

      还有其他很酷的过渡,例如 ScaleTransition、SizeTransition、FadeTransition

      【讨论】:

        【解决方案3】:

        如果您需要使用 IndexedStack。

        您可以添加自定义动画并在更改选项卡时触发它,如下所示:

        import 'package:flutter/material.dart';
        
        void main() => runApp(MyApp());
        
        class MyApp extends StatelessWidget {
          @override
          Widget build(BuildContext context) {
            return MaterialApp(
              title: 'Flutter Demo',
              theme: ThemeData(
                primarySwatch: Colors.blue,
              ),
              home: MyHomePage(),
            );
          }
        }
        
        class MyHomePage extends StatefulWidget {
          @override
          _MyHomePageState createState() => _MyHomePageState();
        }
        
        class _MyHomePageState extends State<MyHomePage> with TickerProviderStateMixin {
          final List<Widget> myTabs = [
            Tab(text: 'one'),
            Tab(text: 'two'),
            Tab(text: 'three'),
          ];
        
          AnimationController _animationController;
          TabController _tabController;
          int _tabIndex = 0;
          Animation animation;
        
          @override
          void dispose() {
            _tabController.dispose();
            super.dispose();
          }
        
          @override
          void initState() {
            _tabController = TabController(length: 3, vsync: this);
            _animationController = AnimationController(
              vsync: this,
              value: 1.0,
              duration: Duration(milliseconds: 500),
            );
            _tabController.addListener(_handleTabSelection);
            animation = Tween(begin: 0.0, end: 1.0).animate(_animationController);
            super.initState();
          }
        
          _handleTabSelection() {
            if (!_tabController.indexIsChanging) {
              setState(() {
                _tabIndex = _tabController.index;
              });
              _animationController.reset();
              _animationController.forward();
            }
          }
        
          @override
          Widget build(BuildContext context) {
            List<Widget> _tabs = [
              MyAnimation(
                animation: animation,
                child: Text('first tab'),
              ),
              MyAnimation(
                animation: animation,
                child: Column(
                  children: List.generate(20, (index) => Text('line: $index')).toList(),
                ),
              ),
              MyAnimation(
                animation: animation,
                child: Text('third tab'),
              ),
            ];
        
            return Scaffold(
              appBar: AppBar(),
              bottomNavigationBar: TabBar(
                controller: _tabController,
                labelColor: Colors.redAccent,
                isScrollable: true,
                tabs: myTabs,
              ),
              body: IndexedStack(
                children: _tabs,
                index: _tabIndex,
              ),
            );
          }
        }
        
        class MyAnimation extends AnimatedWidget {
          MyAnimation({key, animation, this.child})
              : super(
                  key: key,
                  listenable: animation,
                );
        
          final Widget child;
        
          @override
          Widget build(BuildContext context) {
            Animation<double> animation = listenable;
            return Opacity(
              opacity: animation.value,
              child: child,
            );
          }
        }
        

        【讨论】:

        • 是的,我知道这就是它不切换的原因。但我需要保留选项卡的状态,而我发现这样做的唯一方法是使用 IndexedStack。您是否知道 IndexedStack 的任何替代方案,它们可以维护选项卡的状态并与 AnimatedSwitcher 兼容?
        • 您可以在上层保存标签状态并从那里向下传递。您需要存储什么样的数据?
        • 大多数选项卡都包含例如一个列表视图,我想为其保留滚动位置。如果我要在上层保存选项卡状态,如果我的 tabPage 是使用 namedRoutes 的主路由,我该怎么做?
        • 持久状态和状态管理本身就是大主题。在您的情况下,使用 indexedState 可能会很好。
        • @Kherel 非常感谢,您节省了我的时间,我们可以用reveal effect 代替吗?
        【解决方案4】:

        这是将IndexedStack 与动画一起使用的更简洁的方式,我创建了一个FadeIndexedStack 小部件。

        https://gist.github.com/diegoveloper/1cd23e79a31d0c18a67424f0cbdfd7ad

        用法

        body: FadeIndexedStack(  
            //this is optional
            //duration: Duration(seconds: 1),
            children: _tabs.map((t) => t.widget).toList(),  
            index: _currentIndex,  
          ),  
        
        

        【讨论】:

        • 你拯救了我的一天!谢谢!
        【解决方案5】:

        尝试将键添加到您的 IndexedStack,这样您的代码将如下所示:

        body: AnimatedSwitcher(  
          duration: Duration(milliseconds: 200),  
          child: IndexedStack(
            key: ValueKey<int>(_currentIndex),
            children: _tabs.map((t) => t.widget).toList(),  
            index: _currentIndex,  
          ),  
        )
        

        密钥已更改,因此 AnimatedSwitcher 将知道它的孩子需要重建。

        【讨论】:

        • 这不能按预期工作,因为它不会在 IndexedStack 中切换的小部件之间保持状态
        猜你喜欢
        • 2020-01-01
        • 2020-10-30
        • 2020-06-13
        • 1970-01-01
        • 1970-01-01
        • 2020-08-08
        • 1970-01-01
        • 2020-08-08
        • 2020-08-25
        相关资源
        最近更新 更多