flutterdartanimatedcontainer

Flutter: Animating Row contents within a stateless widget


I have a Row that is made out of either one or two elements. Depending on the latter, I want to animate the width of the first element to either be fully expanded, or to accommodate for the second element.

I am using AnimatedContainers within the row to achieve this, but there is no animation. I thought this probably has to do with Flutter not recognizing it as the same after re-rendering based on its parent's state, so I tried using a Unique Key. This however didn't work either.

class TabsBar extends StatelessWidget {
  TabsBar({this.currentIndex, this.onIndexChanged, Key key}) : super(key: key);
  final int currentIndex;
  final Function(int) onIndexChanged;

  @override
  Widget build(BuildContext context) {
    final tabsBloc = BlocProvider.of<TabsBarBloc>(context);

  return BlocBuilder<TabsBarBloc, TabsBarBlocState>(
    builder: (context, tabsBarState) {
  return SafeArea(
    child: Padding(
      padding: const EdgeInsets.symmetric(horizontal: standardSpacing),
      child: Row(
        children: [
          Expanded(
            child: AnimatedContainer(
              key: key,
              height: 60,
              duration: Duration(milliseconds: 200),
              //....//
          ),
          //HERE: IF INDEX IS == 2, I WANT THE CONTAINER ABOVE TO ANIMATE INTO ITS NEW SIZE WHICH IS LESS WIDE TO ACCOMMODATE FOR THE CONTAINER BELOW
          currentIndex == 2
              ? GestureDetector(
                  onTap: () {},
                  behavior: HitTestBehavior.translucent,
                  child: AnimatedContainer(
                    duration: Duration(milliseconds: 200),
                    padding: const EdgeInsets.only(left: standardSpacing),
                    height: 60,
                    child: Image.asset(
                      '${imagesPath}add_piece.png',
                    ),
                  ),
                )
              : HorizontalSpacing(0),
        ],
      ),
    ),
  );
});

I also tried using a Layout Builder to define the width explicitly and using an Animated Container as a parent to the Row. Neither worked.

Can anybody point me towards what I might be missing?


Solution

  • I don't fully understand what value of the AnimatedContainer are you trying to change but it could be easier to just animate the second container of the row and change it's width to 0 so it dissapears from the screen

    class Home extends StatefulWidget {
      @override
      State<Home> createState() => HomeState();
    }
    
    class HomeState extends State<Home> {
      int currentIndex = 2; //or you could use a boolean type
    
      @override
      Widget build(BuildContext context) {
        return Column(mainAxisSize: MainAxisSize.min, children: [
          MyWidget(
            currentIndex: currentIndex,
          ),
          FlatButton(
              onPressed: () => setState(() {
                    currentIndex = currentIndex == 1 ? 2 : 1;
                  }),
              child: Text('Change'))
        ]);
      }
    }
    
    class MyWidget extends StatelessWidget {
      final int currentIndex;
      static const double standardSpacing = 8.0;
    
      MyWidget({this.currentIndex, Key key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return SafeArea(
          child: Padding(
            padding: const EdgeInsets.symmetric(horizontal: standardSpacing),
            child: Row(
              children: [
                Expanded(
                 child: Container( //Normal Container
                   height: 60,
                   color: Colors.blue)
                ),
                GestureDetector(
                  onTap: () {},
                  behavior: HitTestBehavior.translucent,
                  child: AnimatedContainer(
                    duration: Duration(milliseconds: 200),
                    padding: const EdgeInsets.only(left: standardSpacing),
                    height: 60,
                    width: currentIndex == 2 ? 36 : 0, //when currentIndex is not 2, it's size its zero
                    child: const Icon(Icons.save),
                  ),
                )
              ],
            ),
          ),
        );
      }
    }