MBK
MBK

Reputation: 3414

Animated Container with dynamix height Flutter

I am using an animatedContainer to reveal a listView.builder() when a button is pressed. It's a simple sublist to show, but the problem is the height of the ListView builder is not known by me to pass to animatedContainer height Constraint. Do there any way to get the height of the listview builder dynamically or any other method to achieve this?

What I need?

Something like this: https://getbootstrap.com/docs/4.0/components/collapse/

AnimatedContainer(
duration: Duration(milliseconds: 200),
curve: Curves.easeIn,
height: _expanded ? 150 : 0, // This height I cannot set here explicitly. I need to set dynamically like, get child's height
child: ListView.builder(
  key: listViewKey,
  shrinkWrap: true,
  scrollDirection: Axis.vertical,
  physics: const NeverScrollableScrollPhysics(),
  itemCount: loadedSubCategories.length,
  itemBuilder: (ctx, i) => ChangeNotifierProvider.value(
  value: loadedSubCategories[i],
  child: SubCategoryItem(loadedSubCategories[i].categoryId,
     loadedSubCategories[i].subCategoryId)),
  ),
),

While I am using a normal Container(), I wont set the height: property so that it will get the child's height automatically but I need the height because I would like to expanded the subcategories in a animated way.

Each element of SubCategories having different heights and the number of Subcategories is also Unknown. so calculating the height with subcategories.length is also not possible.

Any advice is really appreciated, Thank you

Upvotes: 1

Views: 5562

Answers (3)

Amir Khasru Tasnim
Amir Khasru Tasnim

Reputation: 174

Instead of using AnimatedContainer you can use AnimatedCrossFade

Like this

AnimatedCrossFade(
duration: Duration(milliseconds: 200),
curve: Curves.easeIn,
  crossFadeState: _expanded ? CrossFadeState.showFirst : CrossFadeState.showSecond,
                                          
firstChild: ListView.builder(
  key: listViewKey,
  shrinkWrap: true,
  scrollDirection: Axis.vertical,
  physics: const NeverScrollableScrollPhysics(),
  itemCount: loadedSubCategories.length,
  itemBuilder: (ctx, i) => ChangeNotifierProvider.value(
  value: loadedSubCategories[i],
  child: SubCategoryItem(loadedSubCategories[i].categoryId,
     loadedSubCategories[i].subCategoryId)),
  ),
 secondChild: Container(),
),

This works for me.

Upvotes: 1

R3HP
R3HP

Reputation: 510

you can achieve what you're looking for with AnimatedSize widget .

it automatically creates a widget that animates itself to match it's child size and you don't need to provide any height or width to it. you just need to wrap your widget with it

AnimatedSize(
            curve: Curves.fastOutSlowIn,
            duration: Duration(milliseconds: 300),
            vsync: this,
            child: Container()
)

you can have look at for more information.

Upvotes: 18

Balasubramani Sundaram
Balasubramani Sundaram

Reputation: 1290

enter image description here

Using the Curves.fastLinearToSlowEaseIn and SizeBox.shrink to achieve your requirement

@override
Widget build(BuildContext context) {
  return SafeArea(
    bottom: true,
    top: false,
    child: Scaffold(
      appBar: AppBar(
        title: Text('Container'),
      ),
      body: Column(
        children: [
          Center(
            child: FlatButton(
                onPressed: () {
                  setState(() {
                    _expanded = true;
                  });
                },
                child: Text('expand')),
          ),
          AnimatedContainer(
            duration: Duration(seconds: 2),
            curve: Curves.fastLinearToSlowEaseIn,
            height: _expanded ? 150 : 0,
            clipBehavior: Clip.antiAlias,
            decoration: BoxDecoration(
                color: Colors.white
            ),
            child: _expanded ?  ListView.builder(
                shrinkWrap: true,
                scrollDirection: Axis.vertical,
                physics: const NeverScrollableScrollPhysics(),
                itemCount: 3,
                itemBuilder: (ctx, i) {
                  return ListTile(
                    title: Text(i.toString()),
                  );
                }) : SizedBox.shrink(),
          ),
        ],
      )
    ),
  );
}

Upvotes: 0

Related Questions