How to Automatically Scroll down when expanding ExpansionTile

1,290

You can create your own ScrollController and pass it to ListView, then when ExpansionTile expands, use onExpansionChanged to animate the controller and scroll a bit down

class ListViewExample extends StatefulWidget {
  ListViewExample({Key key}) : super(key: key);

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

class _ListViewExampleState extends State<ListViewExample> {
  final ScrollController scroll = ScrollController();

  @override
  void dispose() {
    scroll.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return ListView(
      controller: scroll,
      children: [
        ListTile(
          subtitle: Image.asset('assets/images/lunch-logo.jpg'),
          title:  ElevatedButton(
            child: Text('Back'),
            onPressed: () {
              Navigator.push(
                context,
                MaterialPageRoute(builder: (context) => HomeRoute()),
              );
            },
          ),
        ),
        ListTile(
          //leading: Image.asset('assets/images/lunch-logo.jpg'),
          subtitle: Text('Enjoy our Lunch Options!',
            style: TextStyle(
              fontSize: 18.0,
              color: Colors.blue,
              fontWeight: FontWeight.w600,
            ) ,
            textAlign: TextAlign.center ,
          ),
        ),
        ExpansionTile(
          leading: Text(
              'Starters',
              style: TextStyle(
              fontSize: 18.0,
              color: Colors.blue,
              fontWeight: FontWeight.w600,
            ),
          ),
          onExpansionChanged: (value) {
            if (value)
              scroll.animateTo(120, //this is a hardcoded value, would need some tweaking
                duration: const Duration(milliseconds: 300),
                curve: Curves.linear);
          },
          children: [
            ... //Your widgets
          ],
        )
      ],
    );
  }
}

onExpansionChanged returns true when its expanding and false when collapsing, you can use those values and check the scroll offset to know if you need to animate the scroll to move downward

Share:
1,290
John
Author by

John

Updated on December 01, 2022

Comments

  • John
    John over 1 year

    I am making my first Flutter App; enjoying it thus far. One annoying thing that I can not quite put my finger on, is that I have some ExpandedTiles, like so: Layout of Screen, with lists not expanded

    However, when the tile is expanded, the screen stays in the same position; like so:

    After expanding

    What I would like, is if the app is scrolled down aa little bit when the ExpandedView is expanded.

    Desired placement after Expanding.

    I found this previous question, How to scroll an ExpansionTile / Listview when a tile is expanded? but that is a little different in that it just creates a list of the same items every time. I want the same functionality, but for 3 or 4 unique lists.

     Widget build(BuildContext context) {
    final title = 'Lunch Menu';
    
    return MaterialApp(
      title: title,
      home: Scaffold(
        appBar: AppBar(
          title: Text(title),
        ),
        body:
        ListView(
          children:
        <Widget>[
            ListTile(
              subtitle: Image.asset('assets/images/lunch-logo.jpg'),
              title:  ElevatedButton(
                child: Text('Back'),
                onPressed: () {
                  Navigator.push(
                    context,
                    MaterialPageRoute(builder: (context) => HomeRoute()),
                  );
                },
              ),
            ),
            ListTile(
              //leading: Image.asset('assets/images/lunch-logo.jpg'),
              subtitle: Text('Enjoy our Lunch Options!',
                style: TextStyle(
                  fontSize: 18.0,
                  color: Colors.blue,
                  fontWeight: FontWeight.w600,
                ) ,
                textAlign: TextAlign.center ,
            ),
            ),
    
            ExpansionTile(
              leading: Text(
                'Starters',
                style: TextStyle(
                fontSize: 18.0,
                color: Colors.blue,
                fontWeight: FontWeight.w600,
              ),
            ),
              children:<Widget>[ ListTile(
                leading: Image.asset('assets/images/food/image1.png'),
                title: Text('Title1'),
                isThreeLine: true,
                subtitle: Text('Description 1') ,
              ),ListTile(
                leading: Image.asset('assets/images/food/image2.png'),
                title: Text('Title2'),
                isThreeLine: true,
                subtitle: Text('Description2') ,
              ),
    

    Would appreciate if someone can give me a pointer on how to implement the scroll controller correctly.

  • John
    John over 3 years
    Thank you, this is pretty good. One thing that isn't quite right, is when it expands, it scrolls to the desired position; but then 'frisbees' back to the initial spot. Should I try playing with that 120? I made it bigger and smaller, but same effect.
  • EdwynZN
    EdwynZN over 3 years
    Maybe adding a future delayed to wait the expanded tile to finish the animation before scrolling