Flutter - Collapsing ExpansionTile after choosing an item

后端 未结 6 1409
傲寒
傲寒 2020-11-27 20:04

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 onExpansio

6条回答
  •  庸人自扰
    2020-11-27 20:53

    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 {
    
        final GlobalKey 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: [
                            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 [],
            this.trailing,
            this.initiallyExpanded: false,
        })
            : assert(initiallyExpanded != null),
                super(key: key);
    
        final Widget leading;
        final Widget title;
        final ValueChanged onExpansionChanged;
        final List children;
        final Color backgroundColor;
        final Widget trailing;
        final bool initiallyExpanded;
    
        @override
        AppExpansionTileState createState() => new AppExpansionTileState();
    }
    
    class AppExpansionTileState extends State with SingleTickerProviderStateMixin {
        AnimationController _controller;
        CurvedAnimation _easeOutAnimation;
        CurvedAnimation _easeInAnimation;
        ColorTween _borderColor;
        ColorTween _headerColor;
        ColorTween _iconColor;
        ColorTween _backgroundColor;
        Animation _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(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((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: [
                        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),
            );
        }
    }
    

提交回复
热议问题