10

I have an indexed stack. First child widget has half the content that the second child widget has, but the first child widget's height is the same as the second child widget. This seems to be the expected result due to the design but its annoying because when I scroll on the first child widget, there is a bunch of extra space at the bottom. How can I work around this?

Why did the Flutter team even design it like this? Why not give the widget children the height according the the widgets, not according to whatever the largest child is?

TortillaPack
  • 155
  • 2
  • 11

5 Answers5

7

This solution preserves state, one of the key features of IndexedStack. Most of the posted solutions drop state on index change, and I needed to preserve state.

The Widget height has no restriction if active, and is constrained to a 1 pixel SizedBox if inactive. This makes the active Widget largest, so your Widget is rendered at it's personal size without added space.

IndexedStack(
  index: selectedIndex,
  children: [
    SizedBox(
        height: selectedIndex == 0 ? null : 1,
        child: Widget1()),
    SizedBox(
        height: selectedIndex == 1 ? null : 1,
        child: Widget2()),
    SizedBox(
        height: selectedIndex == 2 ? null : 1,
        child: Widget3())
  ],
);
Dylan Cross
  • 544
  • 2
  • 6
  • 14
4

you can use visibility inside a IndexedStack. Like this:

IndexedStack(
  index: selectedIndex,
  children: [
    Visibility(
     visible: selectedIndex == 0,
     child: Container(
       height: 300,
     ),
    Visibility(
      visible: selectedIndex == 1,
      child: Container(
      height: 100,
    )
  ]
)

you can do this inside a column too just replace indexedstack with column.

imran sifat
  • 165
  • 1
  • 13
  • 1
    This works very well if you don't need to preserve state of the child widgets. If you need the state preservation feature of IndexedStack, choose another option. – Dylan Cross Nov 04 '22 at 16:18
1

Co ask. I am experiencing this problem when I have the index stack as one of the slivers in a custom scroll view. The children are wash scrollable lists. So when one child of the indexed stack has more items in its list than the other, there is extra white space at the bottom

kingkobain99
  • 197
  • 2
  • 15
1

I faced the exact same issue today. My workaround is to only render the Stack which is visible based on the index number.

      Widget _buildPage2() {
        if(index != 1) { // Empty container
          return Container();
        }
        return Column( // Actual Widget which has a different height
          children: <Widget>[]
        );
     }

I still have not figured out how to get controller.animateTo working.

Edit

I got controller.animateTo to work by triggering a Future.delayed event. As a better approach you could use WidgetBindings, as explained in this other post.

Souvik Das
  • 36
  • 5
0

I faced the same issue and found this workaround.

class CustomIndexedStack extends StatelessWidget {
  const CustomIndexedStack(
      {super.key, required this.index, required this.children});

  final List<Widget> children;
  final int index;

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: children
          .mapIndexed(
              (widget, i) => Offstage(offstage: index != i, child: widget))
          .toList(),
    );
  }
}

extension IndexedIterable<E> on Iterable<E> {
  Iterable<T> mapIndexed<T>(T Function(E e, int i) f) {
    var i = 0;
    return map((e) => f(e, i++));
  }
}
Florian
  • 1
  • 1