Forem

Cover image for Exploring Simple Widgets I: The Expansion Tile
Alpha
Alpha

Posted on

3

Exploring Simple Widgets I: The Expansion Tile

What is the Expansion Tile Widget?

The Expansion Tile Widget is a part of the Flutter material library that allows developers to create a collapsible tile with two states: expanded and collapsed. It is widely used to create lists with items that can expand or collapse to reveal more content. This widget is particularly useful when dealing with limited screen space and the need to display additional information when required.

How does it work?

The Expansion Tile Widget consists of a header and a body. When the user taps on the header, the widget expands, revealing the content inside the body. Subsequently, another tap collapses the widget, hiding the content. Think of things like FAQ section where the answer to a question is revealed when the question tile is clicked on or a Post that reveals more info (or a comment section) when clicked.

How to use the Expansion Tile

To use the Expansion Tile Widget, simply add it to the body of your scaffold. It has a single required title parameter which takes a widget (so it could be literally any widget). It shows the title of the Expansion tile.

class Home extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Expansion Tile'),
      ),
      body: Center(
        // our Expansion Tile here
        child: ExpansionTile(
          title: Text('Hey, I can Expand'),

        ),
      ) );
  }
}

Enter fullscreen mode Exit fullscreen mode

Collapsed State

Expanded State but Empty

Although we can see the change when we click on the tile, it doesn't exactly expand. That's because we haven't added the hidden items.

To add the hidden items to be revealed, we have a children property that takes in a List of widgets.

 ExpansionTile(
          title: Text('Hey, I Expand'),
          //adding the hidden items
          children: [
            ListTile(
              title: Text('Can you see me? I am a ListTile'),
              trailing: Icon(Icons.waving_hand)
            ),
             SizedBox(height: 10,),
            Text('I am a boring Text'),
            SizedBox(height: 10,),
            CircleAvatar(
              radius: 25,
              child: CircleAvatar(
                radius: 20,
                backgroundColor: Colors.white,
                child: FlutterLogo()),
            )
          ],
        ),
Enter fullscreen mode Exit fullscreen mode

Expanded state with Children

Well, that's basically all you need to do to use the ExpansionTile widget. But there are other fun stuff to play around with.
As you can see, there's a default expand more(arrow down) and expand less(arrow down) icon when we expand and collapse the tile, we can use our preferred Icon(or widget) using the trailing parameter or nothing at all by just setting the value to a SizedBox.
There's also an onExpansionChanged parameter which takes a function with a boolean param that basically tells us the state of the tile and we can do something in this function when we change the state of the tile.

class Home extends StatefulWidget {
  @override
  State<Home> createState() => _HomeState();
}

class _HomeState extends State<Home> {
  bool isExpanded = false;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Expansion Tile'),
      ),
      body: Center(
        child: ExpansionTile(
          title: Text('Hey, I Expand'),
          trailing: Text(isExpanded ? 'close' : 'open'),
          //adding the hidden items
          onExpansionChanged: (val){
            setState((){
              isExpanded = val;
            });
          },
          children: [
            ListTile(
              title: Text('Can you see me? I am a ListTile'),
              trailing: Icon(Icons.waving_hand)
            ),
             SizedBox(height: 10,),
            Text('I am a boring Text'),
            SizedBox(height: 10,),
            CircleAvatar(
              radius: 25,
              child: CircleAvatar(
                radius: 20,
                backgroundColor: Colors.white,
                child: FlutterLogo()),
            )
          ],
        ),
      ) );
  }
}
Enter fullscreen mode Exit fullscreen mode

Collapsed tile with custom trailing

Expanded tile with custom trailing

In the snippet above, we changed our Home to a stateful widget so we could update our trailer from open to closed using setState((){}) when the tile changes.

There are other interesting attributes in the Expansion tile which includes boolean values intiallyExpanded for specifying the initial state of the tile and maintainState to specify whether the children widget be kept in the widget tree or recreated each time the tile is Expanded.
There is also the tilePadding for specifying the padding of the Expansion tile and childrenPadding for the children's padding.
Other values are provided are for styling our ExpansionTile includes such as the colors and shapes.

Here's a full list of all its Attributes:

(new) ExpansionTile ExpansionTile({
  Key? key,
  Widget? leading,
  required Widget title,
  Widget? subtitle,
  void Function(bool)? onExpansionChanged,
  List<Widget> children = const <Widget>[],
  Widget? trailing,
  bool initiallyExpanded = false,
  bool maintainState = false,
  EdgeInsetsGeometry? tilePadding,
  CrossAxisAlignment? expandedCrossAxisAlignment,
  Alignment? expandedAlignment,
  EdgeInsetsGeometry? childrenPadding,
  Color? backgroundColor,
  Color? collapsedBackgroundColor,
  Color? textColor,
  Color? collapsedTextColor,
  Color? iconColor,
  Color? collapsedIconColor,
  ShapeBorder? shape,
  ShapeBorder? collapsedShape,
  Clip? clipBehavior,
  ListTileControlAffinity? controlAffinity,
})
Enter fullscreen mode Exit fullscreen mode

Nesting Expansion Tiles

A common question that comes to mind is whether we can nest multiple expansion tiles in each other.Yes we can! However, while this is possible, it is advisable to limit the depth of the nesting to avoid overwhelming the user and to maintain a clear interface.

class Home extends StatefulWidget {
  @override
  State<Home> createState() => _HomeState();
}

class _HomeState extends State<Home> {
  bool isExpanded = false;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Expansion Tile'),
      ),
      body: Center(
        child: Column(
          children: [
            ExpansionTile(
              controlAffinity: ListTileControlAffinity.trailing,
              title: Text('Hey, I Expand'),
              initiallyExpanded: true,
              maintainState: true,
              subtitle: Text('Click me'),
              trailing: Text(isExpanded ? 'close' : 'open'),
              //adding the hidden items
              onExpansionChanged: (val){
                setState((){
                  isExpanded = val;
                });
              },
              children: [
                ListTile(
                  title: Text('Can you see me? I am a ListTile'),
                  trailing: Icon(Icons.waving_hand)
                ),
                 SizedBox(height: 10,),
                Text('I am a boring Text'),
                SizedBox(height: 10,),
                CircleAvatar(
                  radius: 25,
                  child: CircleAvatar(
                    radius: 20,
                    backgroundColor: Colors.white,
                    child: FlutterLogo()),
                )
              ],
            ),
            ExpansionTile(
  title: Text('Parent Tile'),
  children: [
    ExpansionTile(
      title: Text('Child Tile 1'),
      children: [
        ListTile(
          title: Text('Content 1'),
        ),
      ],
    ),
    ExpansionTile(
      title: Text('Child Tile 2'),
      children: [
        ListTile(
          title: Text('Content 2'),
        ),
      ],
    ),
  ],
)
          ],
        ),
      ) );
  }
}

Enter fullscreen mode Exit fullscreen mode

Multiple Expansion Tiles

Nested Expansion Tile depth 1

Nested Expansion Tile depth 2

Conclusion

The Expansion Tile Widget in Flutter provides developers with a powerful tool to create collapsible and expandable content areas, enhancing user experience and improving UI design. By customizing the widget's appearance and behaviour, developers can create intuitive and engaging interfaces for their Flutter applications.

Checkout an interesting use of Expansion Tile in the GitHub gist below:
Github Gist

Please suggest in the comment what Widget I should look into next. Thank you

Image of Timescale

🚀 pgai Vectorizer: SQLAlchemy and LiteLLM Make Vector Search Simple

We built pgai Vectorizer to simplify embedding management for AI applications—without needing a separate database or complex infrastructure. Since launch, developers have created over 3,000 vectorizers on Timescale Cloud, with many more self-hosted.

Read more

Top comments (1)

Collapse
 
laposhstylez profile image
Laposhstylez

Detailed explanations

Billboard image

📊 A side-by-side product comparison between Sentry and Crashlytics

A free guide pointing out the differences between Sentry and Crashlytics, that’s it. See which is best for your mobile crash reporting needs.

See Comparison

👋 Kindness is contagious

Dive into an ocean of knowledge with this thought-provoking post, revered deeply within the supportive DEV Community. Developers of all levels are welcome to join and enhance our collective intelligence.

Saying a simple "thank you" can brighten someone's day. Share your gratitude in the comments below!

On DEV, sharing ideas eases our path and fortifies our community connections. Found this helpful? Sending a quick thanks to the author can be profoundly valued.

Okay