带有 IndexedStack 的 AnimatedSwitcher

Rev*_*Plz 10 flutter flutter-layout flutter-animation

我必须使用 IndexedStack 来维护我的底部导航栏的小部件的状态。现在我想在切换选项卡时使用 AnimatedSwitcher(或替代方法)来创建动画。我在让 AnimatedSwitcher 在 IndexedStack 更改时触发时遇到问题。我将 IndexedStack 作为 AnimatedSwitcher 的子级,这显然会导致 AnimatedSwitcher 无法触发,因为 IndexedStack 小部件没有改变,只是它的子级。

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

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

die*_*per 24

这是一种更简洁的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,  
  ),  

Run Code Online (Sandbox Code Playgroud)

  • 你是我的英雄。非常好的作品!Flutter 应该在他们的框架中实现这一点!非常感谢,非常感谢。 (2认同)

Khe*_*rel 8

如果您需要使用 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,
    );
  }
}
Run Code Online (Sandbox Code Playgroud)