Expandable widget in sliver list expands to the top instead of to the bottom due to center key

Viewed 37

I want to make expandable item in sliver list, but when the expandable widget is in sliver list above the sliver list with center key, expandable item expands to the top instead to the bottom.

CustomScrollView(
        center: _centerKey,
        slivers: [
// in this sliver list expandable expands to the top
          SliverList(
              delegate: SliverChildListDelegate(
            buildItems(1),
          )),
          SliverList(
// in this sliver list expandable expands to the bottom
              key: _centerKey,
              delegate: SliverChildListDelegate(
                buildItems(2),
              )),
// in this sliver list expandable expands also to the bottom
          SliverList(
              delegate: SliverChildListDelegate(
            buildItems(3),
          )),
        ],
      );

in buildItems are basic Containers and one Expandable Widget from https://pub.dev/packages/expandable

List<Widget> buildItems(int listIndex) {
      final items = <Widget>[];
      for (int i = 0; i < 10; i++) {
        if (i == 5) {
// Expandable widget
          items.add(const ExpandedItem());
        } else {
          items.add(Container(
            width: double.infinity,
            height: 200,
            color: (i % 2 == 0) ? Colors.blue : Colors.red,
          ));
        }
      }

      return items;
    }

After clicking on yellow item, item goes to the top instead of stay at the same place (orange and brown are expanded content)

after clicking on yellow item, item goes to the top instead of stay at the same place (oragne and brown are expanded content)

class ExpandedItem extends StatefulWidget {
  const ExpandedItem({Key? key}) : super(key: key);

  @override
  State<ExpandedItem> createState() => _ExpandedItemState();
}

class _ExpandedItemState extends State<ExpandedItem> {
  final controller = ExpandableController();
  List<Widget> buildItems() {
    final items = <Widget>[];
    for (int i = 0; i < 10; i++) {
      items.add(GestureDetector(
        onTap: i == 9
            ? () {
                controller.toggle();
              }
            : null,
        child: Container(
          width: double.infinity,
          height: 100,
          color: (i % 2 == 0) ? Colors.orange : Colors.brown,
        ),
      ));
    }

    return items;
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        ExpandableNotifier(
          controller: controller,
          child: Expandable(
            collapsed: GestureDetector(
              onTap: () {
                controller.toggle();
              },
              child: Container(
                color: Colors.yellow,
                width: double.infinity,
                height: 100,
              ),
            ),
            expanded: Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                Container(
                  color: Colors.yellow,
                  width: double.infinity,
                  height: 100,
                ),
                ...buildItems()
              ],
            ),
          ),
        ),
      ],
    );
  }
}

1 Answers

check this when the yellow is tapped, it expand downward

class _ShowCaseState extends State<ShowCase> {
  final Key _centerKey = const ValueKey<String>('bottom-sliver-list');

  List<Widget> buildItems(int listIndex) {
    final items = <Widget>[];
    for (int i = 0; i < 10; i++) {
      if (i == 5) {
        items.add(const ExpandedItem());
      } else {
        items.add(Container(
          width: double.infinity,
          height: 200,
          color: (i % 2 == 0) ? Colors.blue : Colors.red,
        ));
      }
    }

    return items;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: CustomScrollView(
      center: _centerKey,
      slivers: [
// in this sliver list expandable expands to the top
        SliverList(
            key: _centerKey, //here
            delegate: SliverChildListDelegate(
          buildItems(1),
        )),
        SliverList(
// in this sliver list expandable expands to the bottom
            delegate: SliverChildListDelegate(
              buildItems(2),
            )),
// in this sliver list expandable expands also to the bottom
        SliverList(
            delegate: SliverChildListDelegate(
          buildItems(3),
        )),
      ],
    ));
  }
}

class ExpandedItem extends StatefulWidget {
  const ExpandedItem({Key? key}) : super(key: key);

  @override
  State<ExpandedItem> createState() => _ExpandedItemState();
}

class _ExpandedItemState extends State<ExpandedItem> {
  final controller = ExpandableController();
  List<Widget> buildItems() {
    final items = <Widget>[];
    for (int i = 0; i < 10; i++) {
      items.add(GestureDetector(
        onTap: i == 9
            ? () {
                controller.toggle();
              }
            : null,
        child: Container(
          width: double.infinity,
          height: 100,
          color: (i % 2 == 0) ? Colors.orange : Colors.brown,
        ),
      ));
    }

    return items;
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        ExpandableNotifier(
          controller: controller,
          child: Expandable(
            collapsed: GestureDetector(
              onTap: () {
                controller.toggle();
              },
              child: Container(
                color: Colors.yellow,
                width: double.infinity,
                height: 100,
              ),
            ),
            expanded: Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                Container(
                  color: Colors.yellow,
                  width: double.infinity,
                  height: 100,
                ),
                ...buildItems()
              ],
            ),
          ),
        ),
      ],
    );
  }
}
Related