ExpansionPanel
官方提供的一个扩展面板的控件,使用它能够轻松实现展开收起的功能。数组
ExpansionPanel({ @required this.headerBuilder, @required this.body, this.isExpanded = false, this.canTapOnHeader = false, }) : assert(headerBuilder != null), assert(body != null), assert(isExpanded != null), assert(canTapOnHeader != null); 复制代码
ExpansionPanel
的构造函数有4个参数:bash
headerBuilder
:header
样式body
:body
样式isExpanded
:是否展开canTapOnHeader
:header
是否可点击Creates an expansion panel to be used as a child for [ExpansionPanelList].
markdown
源码注释提到ExpansionPanel
不能单独使用,要做为ExpansionPanelList
的child
。ide
const ExpansionPanelList({ Key key, this.children = const <ExpansionPanel>[], this.expansionCallback, this.animationDuration = kThemeAnimationDuration, }) : assert(children != null), assert(animationDuration != null), _allowOnlyOnePanelOpen = false, initialOpenPanelValue = null, super(key: key); 复制代码
ExpansionPanelList
的构造函数有3个参数:函数
children
:ExpansionPanel
类型的数组expansionCallback
:点击时的回调,会返回对应点击的index
和当前isExpanded
的值animationDuration
:动画持续时间class Item { String familyName; List<String> fullName; bool isExpanded; Item(this.familyName, this.fullName, this.isExpanded); } List<Item> getDataSource() { return [ Item('张', ['张一一', '张二二', '张三三', '张四四'], false), Item('王', ['王一一', '王二二', '王三三', '王四四'], false), Item('李', ['李一一', '李二二', '李三三', '李四四'], false), Item('赵', ['赵一一', '赵二二', '赵三三', '赵四四'], false), Item('周', ['周一一', '周二二', '周三三', '周四四'], false), Item('吴', ['吴一一', '吴二二', '吴三三', '吴四四'], false), Item('孙', ['孙一一', '孙二二', '孙三三', '孙四四'], false), ]; } 复制代码
List<Item> _dataSource = getDataSource(); @override Widget build(BuildContext context) { return SingleChildScrollView( child: ExpansionPanelList( expansionCallback: (int index, bool isExpanded) { setState(() { _dataSource[index].isExpanded = !isExpanded; }); }, children: _dataSource.map<ExpansionPanel>((Item item) { return ExpansionPanel( canTapOnHeader: true, isExpanded: item.isExpanded, headerBuilder: (BuildContext context, bool isExpanded) { return ListTile( title: Text(item.familyName), ); }, body: ListView.separated( itemBuilder: (BuildContext context, int index) { return Container( padding: EdgeInsets.fromLTRB(15, 10, 15, 10), child: Text(item.fullName[index]), ); }, separatorBuilder: (BuildContext context, int index) { return new Container(height: 1.0, color: Color(0xfff2f2f2)); }, itemCount: item.fullName.length, shrinkWrap: true, physics: NeverScrollableScrollPhysics(), ), ); }).toList(), animationDuration: Duration(microseconds: 100), ), ); } 复制代码
代码简单易懂不作多解释,有几个须要注意的点这里总结下:动画
在build
方法直接return
一个ExpansionPanelList
会发现没有任何内容展现。 Log
提示:RenderListBody must have unlimited space along its main axis.
也就是说要保持RenderListBody
的主轴上必须有无限的空间。这里咱们在外面包一层SingleChildScrollView
来达到主轴无限的空间的目的。ui
注意ListView.separated
中的属性设置。this
shrinkWrap: true, // 多用于嵌套`listView`内容大小不肯定的状况 physics: NeverScrollableScrollPhysics(), // 禁止滚动,这里想要的效果是展开后跟着ExpansionPanelList一块儿滚动而不是内部ListView单独滚动 复制代码
ExpansionPanelList.radio
配合ExpansionPanelRadio
能达到你想要的效果。ExpansionPanelRadio
是ExpansionPanel
的子类,多了一个value
做为惟一标识,用来区分每一个ExpansionPanelRadio
。