Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AnimatedSwitcher with IndexedStack

I have to use IndexedStack to maintain the state of my widgets for my BottomNavigationBar. Now i want to use AnimatedSwitcher (or an alternative) to create an animation when i switch tabs. I'm having issues getting AnimatedSwitcher to trigger on change of IndexedStack. I'm having IndexedStack as the child of AnimatedSwitcher, which obviously causes AnimatedSwitcher to not trigger because the IndexedStack widget doesn't change, only it's child.

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

Is there any way around this issue? By manually triggering the AnimatedSwitcher, or by using a different method to create an animation? I also tried changing the key, but that obviously resulted in it creating a new IndexedStack everytime the a new state was created, and therefor the states of the tabs was lost as well.

like image 962
RevoltPlz Avatar asked Aug 28 '19 14:08

RevoltPlz


People also ask

What is animatedswitcher in flutter?

Flutter - Using AnimatedSwitcher Widget Examples This tutorial shows you how to use AnimatedSwitcher widget in Flutter. AnimatedSwitcher is a widget that can be used for creating animation when switching between two widgets. When a widget is replaced with another, it transitions the new widget in and transitions the previous widget out.

Is there a way to add custom animation to indexedstack?

If you need to use IndexedStack. You can add custom animation and trigger it on changing tabs, like that:

Why doesn't animatedswitcher do a transition between two children?

If the "new" child is the same widget type and key as the "old" child, but with different parameters, then AnimatedSwitcher will not do a transition between them, since as far as the framework is concerned, they are the same widget and the existing widget can be updated with the new parameters.

What is the use of animatedswitcher layoutbuilder?

AnimatedSwitcherLayoutBuilder layoutBuilder: A function that wraps all children (the transitioning out children and the transitioning in child) with a widget that lays all of them out. Defaults to AnimatedSwitcher.defaultLayoutBuilder.


Video Answer


2 Answers

This is a cleaner way to use IndexedStack with animations , I created a FadeIndexedStack widget.

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

Usage

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

like image 65
diegoveloper Avatar answered Sep 19 '22 21:09

diegoveloper


If you need to use IndexedStack.

You can add custom animation and trigger it on changing tabs, like that: enter image description here

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,
    );
  }
}
like image 39
Kherel Avatar answered Sep 16 '22 21:09

Kherel