Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flutter - Collapsing ExpansionTile after choosing an item

Tags:

flutter

dart

I'm trying to get ExpansionTile to collapse after I choose an item, but it does not close the list that was opened.

I tried to use the onExpansionChanged property but I did not succeed

How could you solve this problem?

Insert a gif demonstrating that ExpansionTile does not collapse after choosing an item, and below is also the code used.

enter image description here

import 'package:flutter/material.dart';  void main() {   runApp(new ExpansionTileSample()); }  class ExpansionTileSample extends StatefulWidget {   @override   ExpansionTileSampleState createState() => new ExpansionTileSampleState(); }  class ExpansionTileSampleState extends State<ExpansionTileSample> {   String foos = 'One';    @override   Widget build(BuildContext context) {     return new MaterialApp(       home: new Scaffold(         appBar: new AppBar(           title: const Text('ExpansionTile'),         ),         body: new ExpansionTile(           title: new Text(this.foos),           backgroundColor: Theme.of(context).accentColor.withOpacity(0.025),           children: <Widget>[             new ListTile(               title: const Text('One'),               onTap: () {                 setState(() {                   this.foos = 'One';                 });               },                           ),             new ListTile(               title: const Text('Two'),               onTap: () {                 setState(() {                   this.foos = 'Two';                 });               },                           ),             new ListTile(               title: const Text('Three'),               onTap: () {                 setState(() {                   this.foos = 'Three';                 });               },                           ),           ]         ),       ),     );   } } 
like image 805
rafaelcb21 Avatar asked Feb 22 '18 14:02

rafaelcb21


People also ask

How do you collapse the ExpansionTile in flutter?

Tapping a tile expands or collapses the view of its children.

How do you style an ExpansionTile in flutter?

To change the ExpansionTile color, you can wrap it with a Container and give it a color. This will change the entire color of the ExpansionTile, both collapsed and expanded. But if you want a different color for the children, you can also wrap them with a Container and set another color there.


1 Answers

Here is a solution. We just add a expand, collapse and toggle functionality to ExpansionTile.

import 'package:flutter/material.dart'; import 'package:meta/meta.dart';   void main() {     runApp(new ExpansionTileSample()); }  class ExpansionTileSample extends StatefulWidget {     @override     ExpansionTileSampleState createState() => new ExpansionTileSampleState(); }  class ExpansionTileSampleState extends State<ExpansionTileSample> {      final GlobalKey<AppExpansionTileState> expansionTile = new GlobalKey();     String foos = 'One';      @override     Widget build(BuildContext context) {         return new MaterialApp(             home: new Scaffold(                 appBar: new AppBar(                     title: const Text('ExpansionTile'),                 ),                 body: new AppExpansionTile(                     key: expansionTile,                     title: new Text(this.foos),                     backgroundColor: Theme                         .of(context)                         .accentColor                         .withOpacity(0.025),                     children: <Widget>[                         new ListTile(                             title: const Text('One'),                             onTap: () {                                 setState(() {                                     this.foos = 'One';                                     expansionTile.currentState.collapse();                                 });                             },                         ),                         new ListTile(                             title: const Text('Two'),                             onTap: () {                                 setState(() {                                     this.foos = 'Two';                                     expansionTile.currentState.collapse();                                 });                             },                         ),                         new ListTile(                             title: const Text('Three'),                             onTap: () {                                 setState(() {                                     this.foos = 'Three';                                     expansionTile.currentState.collapse();                                 });                             },                         ),                     ]                 ),             ),         );     } }  // --- Copied and slightly modified version of the ExpansionTile.  const Duration _kExpand = const Duration(milliseconds: 200);  class AppExpansionTile extends StatefulWidget {     const AppExpansionTile({         Key key,         this.leading,         @required this.title,         this.backgroundColor,         this.onExpansionChanged,         this.children: const <Widget>[],         this.trailing,         this.initiallyExpanded: false,     })         : assert(initiallyExpanded != null),             super(key: key);      final Widget leading;     final Widget title;     final ValueChanged<bool> onExpansionChanged;     final List<Widget> children;     final Color backgroundColor;     final Widget trailing;     final bool initiallyExpanded;      @override     AppExpansionTileState createState() => new AppExpansionTileState(); }  class AppExpansionTileState extends State<AppExpansionTile> with SingleTickerProviderStateMixin {     AnimationController _controller;     CurvedAnimation _easeOutAnimation;     CurvedAnimation _easeInAnimation;     ColorTween _borderColor;     ColorTween _headerColor;     ColorTween _iconColor;     ColorTween _backgroundColor;     Animation<double> _iconTurns;      bool _isExpanded = false;      @override     void initState() {         super.initState();         _controller = new AnimationController(duration: _kExpand, vsync: this);         _easeOutAnimation = new CurvedAnimation(parent: _controller, curve: Curves.easeOut);         _easeInAnimation = new CurvedAnimation(parent: _controller, curve: Curves.easeIn);         _borderColor = new ColorTween();         _headerColor = new ColorTween();         _iconColor = new ColorTween();         _iconTurns = new Tween<double>(begin: 0.0, end: 0.5).animate(_easeInAnimation);         _backgroundColor = new ColorTween();          _isExpanded = PageStorage.of(context)?.readState(context) ?? widget.initiallyExpanded;         if (_isExpanded)             _controller.value = 1.0;     }      @override     void dispose() {         _controller.dispose();         super.dispose();     }      void expand() {         _setExpanded(true);     }      void collapse() {         _setExpanded(false);     }      void toggle() {         _setExpanded(!_isExpanded);     }      void _setExpanded(bool isExpanded) {         if (_isExpanded != isExpanded) {             setState(() {                 _isExpanded = isExpanded;                 if (_isExpanded)                     _controller.forward();                 else                     _controller.reverse().then<void>((Null value) {                         setState(() {                             // Rebuild without widget.children.                         });                     });                 PageStorage.of(context)?.writeState(context, _isExpanded);             });             if (widget.onExpansionChanged != null) {                 widget.onExpansionChanged(_isExpanded);             }         }     }      Widget _buildChildren(BuildContext context, Widget child) {         final Color borderSideColor = _borderColor.evaluate(_easeOutAnimation) ?? Colors.transparent;         final Color titleColor = _headerColor.evaluate(_easeInAnimation);          return new Container(             decoration: new BoxDecoration(                 color: _backgroundColor.evaluate(_easeOutAnimation) ?? Colors.transparent,                 border: new Border(                     top: new BorderSide(color: borderSideColor),                     bottom: new BorderSide(color: borderSideColor),                 )             ),             child: new Column(                 mainAxisSize: MainAxisSize.min,                 children: <Widget>[                     IconTheme.merge(                         data: new IconThemeData(color: _iconColor.evaluate(_easeInAnimation)),                         child: new ListTile(                             onTap: toggle,                             leading: widget.leading,                             title: new DefaultTextStyle(                                 style: Theme                                     .of(context)                                     .textTheme                                     .subhead                                     .copyWith(color: titleColor),                                 child: widget.title,                             ),                             trailing: widget.trailing ?? new RotationTransition(                                 turns: _iconTurns,                                 child: const Icon(Icons.expand_more),                             ),                         ),                     ),                     new ClipRect(                         child: new Align(                             heightFactor: _easeInAnimation.value,                             child: child,                         ),                     ),                 ],             ),         );     }      @override     Widget build(BuildContext context) {         final ThemeData theme = Theme.of(context);         _borderColor.end = theme.dividerColor;         _headerColor             ..begin = theme.textTheme.subhead.color             ..end = theme.accentColor;         _iconColor             ..begin = theme.unselectedWidgetColor             ..end = theme.accentColor;         _backgroundColor.end = widget.backgroundColor;          final bool closed = !_isExpanded && _controller.isDismissed;         return new AnimatedBuilder(             animation: _controller.view,             builder: _buildChildren,             child: closed ? null : new Column(children: widget.children),         );     } } 
like image 169
Simon Avatar answered Sep 22 '22 00:09

Simon