Flutter- ExpansionTile单击可展开和折叠 [英] Flutter- ExpansionTile expand and collapse on click

查看:560
本文介绍了Flutter- ExpansionTile单击可展开和折叠的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我以此为参考来扩展和折叠扩展磁贴------- Flutter-选择项目后崩溃ExpansionTile

I am taking this as a reference to expanding and collapsing of expansion tile-------Flutter - Collapsing ExpansionTile after choosing an item

我想要的是,如果一个扩展图块处于打开状态,并且用户单击另一个扩展图块,则其他打开的扩展图块应关闭。

What I want is if I one expansion tile is open and the user clicks on another one the other open expansion tiles should be closed.

我的应用快照

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: GestureDetector(
          onTap: () {
            setState(() {
             // this.foos = 'One';
              expansionTile.currentState.collapse();
            });
          },
          child: Column(
            children: <Widget>[
              new AppExpansionTile(
                  key: expansionTile,
                  title: new Text('1-3'),
                  backgroundColor:
                      Theme.of(context).accentColor.withOpacity(0.025),
                  children: <Widget>[
                    new ListTile(
                      title: const Text('One'),
                    ),
                    new ListTile(
                      title: const Text('Two'),
                    ),
                    new ListTile(
                      title: const Text('Three'),
                    ),
                  ]),
              new AppExpansionTile(
                  title: new Text('4-6'),
                  backgroundColor:
                      Theme.of(context).accentColor.withOpacity(0.025),
                  children: <Widget>[
                    new ListTile(
                      title: const Text('four'),
                    ),
                    new ListTile(
                      title: const Text('five'),
                    ),
                    new ListTile(
                      title: const Text('six'),
                    ),
                  ]),
              new AppExpansionTile(
                  title: new Text('6-9'),
                  backgroundColor:
                      Theme.of(context).accentColor.withOpacity(0.025),
                  children: <Widget>[
                    new ListTile(
                      title: const Text('seven'),
                    ),
                    new ListTile(
                      title: const Text('eight'),
                    ),
                    new ListTile(
                      title: const Text('nine'),
                    ),
                  ]),
            ],
          ),
        ),
      ),
    );
  }
}

// --- 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),
    );
  }
}


推荐答案

您可以使用ExpandablePanelList执行展开和折叠视图。
使用expandingCallback保持活动状态以执行扩展或折叠。
是工作示例

You can use ExpandablePanelList to do perform expand and collapse view. Use expansionCallback to maintain active state to perform expand or collapse. here is the working example

class TestExpandableView extends StatefulWidget {
  @override
  _TestExpandableViewState createState() => _TestExpandableViewState();
}

class _TestExpandableViewState extends State<TestExpandableView> {
  int _activeMeterIndex;
  @override
  Widget build(BuildContext context) {
    return Container(
      child: new ListView.builder(
          itemCount:  2,
          itemBuilder: (BuildContext context, int i) {
            return Card(
              margin:
              const EdgeInsets.fromLTRB(10.0, 15.0, 10.0, 0.0),
              child: new ExpansionPanelList(
                expansionCallback: (int index, bool status) {
                  setState(() {
                    _activeMeterIndex = _activeMeterIndex == i ? null : i;
                  });
                },
                children: [
                  new ExpansionPanel(
                      isExpanded: _activeMeterIndex == i,
                      headerBuilder: (BuildContext context,
                          bool isExpanded) =>
                      new Container(
                          padding:
                          const EdgeInsets.only(left: 15.0),
                          alignment: Alignment.centerLeft,
                          child: new Text(
                            'list-$i',
                          )),
                      body: new Container(child: new Text('content-$i'),),),
                ],
              ),
            );
          }),
    );
  }
}

这篇关于Flutter- ExpansionTile单击可展开和折叠的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆