Flutter - Animate change on height when hide one of Column children
Asked Answered
A

3

10

I have two children inside Column widget, the first one is simple Container and the second on is Expanded widget. User can hide/show the first Container. In this case, I need to apply animation on both widgets, so the height of first container should be reduced automatically and the second widget should be increased gradually until fill the whole space.

I tested to use AnimatedContainer, but it needs to specify its height after and before, which is not known to me.

Any suggestion please?

class ViewerPage extends StatefulWidget {
  @override
  _ViewerPageState createState() => _ViewerPageState();
}

class _ViewerPageState extends State<ViewerPage> {
  bool visible = true;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Example"),
      ),
      bottomNavigationBar: BottomAppBar(
        child: Row(
          mainAxisSize: MainAxisSize.max,
          mainAxisAlignment: MainAxisAlignment.spaceAround,
          children: <Widget>[
            IconButton(
              icon: Icon(Icons.show_chart),
              onPressed: () {
                setState(() {
                  visible = !visible;
                });
              },
            ),
          ],
        ),
      ),
      body: Container(
        child: Column(
          children: <Widget>[
            Visibility(
              visible: visible,
              child: Container(
                  child: Text("This Container can be visible or hidden"),
                  color: Colors.red),
            ),
            Expanded(
              child: ListView.builder(
                itemBuilder: (context, index) => Text("Item ..."),
                itemCount: 20,
              ),
            ),
          ],
        ),
      ),
    );
  }
}
Arthro answered 4/4, 2020 at 21:5 Comment(0)
C
19

Simple, use AnimatedSize, and remove Visibility. AnimatedSize calculates height on its own. so u don't need to know size before and after.

Just pass null for dynamic height and 0 for non visibility. AnimatedSize will take care of the animation

height: visible? null : 0.0,

here, I changed your code a bit. It works fine now.

    import 'package:flutter/material.dart';

    class Test extends StatefulWidget {
      @override
      _TestState createState() => _TestState();
    }

    class _TestState extends State<Test> with SingleTickerProviderStateMixin{

      bool visible = true;
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text("Example"),
          ),
          bottomNavigationBar: BottomAppBar(
            child: Row(
              mainAxisSize: MainAxisSize.max,
              mainAxisAlignment: MainAxisAlignment.spaceAround,
              children: <Widget>[
                IconButton(
                  icon: Icon(Icons.show_chart),
                  onPressed: () {
                    setState(() {
                      visible = !visible;
                    });
                  },
                ),
              ],
            ),
          ),
          body: Container(
            child: Column(
              children: <Widget>[
                AnimatedSize(
                  duration: Duration(seconds: 1),
                  child: Container(
                    height: visible? null : 0.0,
                    child: Text("This Container can be visible or hidden"),
                    color: Colors.red
                  ), 
                  vsync: this,
                ),
                Expanded(
                  child: ListView.builder(
                    itemBuilder: (context, index) => Text("Item ..."),
                    itemCount: 20,
                  ),
                ),
              ],
            ),
          ),
        );
      }
    }
Castra answered 5/4, 2020 at 0:7 Comment(1)
height: null is absolute winner, thanksNitrite
V
5

The accepted solution technically didn't hide the item, it was just collapsed to height of zero, I had a situation where a widget (Icon) appears when the ListView sibling is swiped down.

I recommend the following solution:

AnimatedSize(
duration: const Duration(milliseconds: 500),
child: visible ? Container( child: Text("This Container can be visible or hidden"), color: Colors.red) : const SizedBox(),),

Vedda answered 27/7, 2022 at 18:1 Comment(0)
P
0

Maybe, you guys want to try this. I'm using AnimatedSwitcher and SizeTransition for animation.

In case, you are looking something like looks like ExpansionTile. Check this image https://i.imgur.com/jB1MKlh.gif

import "package:flutter/material.dart";

class Test extends StatefulWidget {
  const Test({super.key});

  @override
  _TestState createState() => _TestState();
}

class _TestState extends State<Test> with SingleTickerProviderStateMixin {
  bool visible = true;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("Example"),
      ),
      bottomNavigationBar: BottomAppBar(
        child: Row(
          mainAxisSize: MainAxisSize.max,
          mainAxisAlignment: MainAxisAlignment.spaceAround,
          children: <Widget>[
            IconButton(
              icon: const Icon(Icons.show_chart),
              onPressed: () {
                setState(() {
                  visible = !visible;
                });
              },
            ),
          ],
        ),
      ),
      body: Column(
        children: <Widget>[
          AnimatedSwitcher(
            duration: const Duration(seconds: 1),
            transitionBuilder: (child, animation) {
              return SizeTransition(
                axisAlignment: 1,
                sizeFactor: animation,
                child: child,
              );
            },
            child: visible
                ? Container(
                    color: Colors.red,
                    child:
                        const Text("This Container can be visible or hidden"),
                  )
                : null,
          ),
          Expanded(
            child: ListView.builder(
              itemBuilder: (context, index) => const Text("Item ..."),
              itemCount: 20,
            ),
          ),
        ],
      ),
    );
  }
}
Pesthole answered 20/9, 2023 at 8:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.