1. 基本介紹
ExpansionPanel澄惊、ExpansionPanelRadio 是一種常見(jiàn)的折疊框唆途。
ExpansionPanelList 是承載折疊框的一個(gè)父類控件。
2. 示例代碼
代碼下載地址掸驱。如果對(duì)你有幫助的話記得給個(gè)關(guān)注肛搬,代碼會(huì)根據(jù)我的 Flutter 專題不斷更新。
3. 屬性介紹
ExpansionPanel 屬性 | 介紹 |
---|---|
headerBuilder | @required毕贼,Header Widget 構(gòu)造方法 |
body | @required温赔,展開(kāi)部分 Widget |
isExpanded | 是否展開(kāi),默認(rèn)為 false |
canTapOnHeader | 是否可以點(diǎn)擊 header 用來(lái)展開(kāi)收起帅刀,false |
ExpansionPanelRadio屬性 | 介紹 |
---|---|
value | @required 唯一標(biāo)識(shí) |
headerBuilder | @required Header Widget 構(gòu)造方法 |
body | @required让腹,展開(kāi)部分 Widget |
canTapOnHeader | 是否可以點(diǎn)擊 header 用來(lái)展開(kāi)收起远剩,false |
ExpansionPanelList屬性 | 介紹 |
---|---|
children | 子控件數(shù)組,類型為 <ExpansionPanel> 的數(shù)組 |
expansionCallback | 點(diǎn)擊折疊收起回調(diào)函數(shù)骇窍,(index, isExpand){}瓜晤,返回當(dāng)前下標(biāo)以及是否折疊 |
animationDuration | 動(dòng)畫(huà)時(shí)間,默認(rèn)為 kThemeAnimationDuration |
expandedHeaderPadding | 展開(kāi)后 Header 的 padding腹纳,默認(rèn)為 _kPanelHeaderExpandedDefaultPadding |
dividerColor | 分割線顏色 |
ExpansionPanelList.radio 屬性 | 介紹
children | 子控件數(shù)組痢掠,類型為 <ExpansionPanelRadio> 的數(shù)組
expansionCallback | 點(diǎn)擊折疊收起回調(diào)函數(shù),(index, isExpand){}嘲恍,返回當(dāng)前下標(biāo)以及是否折疊
initialOpenPanelValue | 當(dāng)前選中標(biāo)識(shí)足画,initialOpenPanelValue == ExpansionPanelRadio.value 時(shí),該 ExpansionPanelRadio 會(huì)默認(rèn)展開(kāi)
animationDuration | 動(dòng)畫(huà)時(shí)間佃牛,默認(rèn)為 kThemeAnimationDuration
expandedHeaderPadding | 展開(kāi)后 Header 的 padding淹辞,默認(rèn)為 _kPanelHeaderExpandedDefaultPadding
dividerColor | 分割線顏色
4. ExpansionPanel,ExpansionPanelList 詳解
4.1 代碼實(shí)現(xiàn)
ExpansionPanel 是單個(gè)折疊框俘侠,他的效果實(shí)現(xiàn)還需要依托于 ExpansionPanelList象缀,這邊直接上 demo,一個(gè)簡(jiǎn)單的折疊框的實(shí)現(xiàn)爷速。
import 'package:flutter/material.dart';
class FMExpansionPanelVC extends StatefulWidget{
@override
FMExpansionPanelState createState() => FMExpansionPanelState();
}
class FMExpansionPanelState extends State <FMExpansionPanelVC>{
List <ExpansionPanelModel> _models = [];
List <ExpansionPanel> _childrenForExpansionPanel = [];
List <ExpansionPanelRadio> _childrenForExpansionPanelRadio = [];
@override
void initState(){
super.initState();
_initData();
}
void _initData(){
_models.clear();
_models.add(ExpansionPanelModel("EP1", "Title EP1", false));
_models.add(ExpansionPanelModel("EP2", "Title EP2", false));
_models.add(ExpansionPanelModel("EP3", "Title EP3", false));
_models.add(ExpansionPanelModel("EP4", "Title EP4", false));
_models.add(ExpansionPanelModel("EP5", "Title EP5", false));
print("initDate");
}
void _initChildrenForExpansionPanel(){
_childrenForExpansionPanel.clear();
_models.forEach((model) {
_childrenForExpansionPanel.add(_expansionPanel(model));
});
}
void _initChildrenForExpansionPanelRadio(){
_childrenForExpansionPanelRadio.clear();
_models.forEach((model) {
_childrenForExpansionPanelRadio.add(_expansionPanelRadio(model));
});
print(_childrenForExpansionPanelRadio);
}
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: Text("ExpansionPanel"),
),
body: SingleChildScrollView(
child: _expansionPanelList(),
),
);
}
ExpansionPanelList _expansionPanelList(){
_initChildrenForExpansionPanel();
return ExpansionPanelList(
expansionCallback: (index, isExpand){
_models[index].isExpanded = !_models[index].isExpanded;
print(_models[index].isExpanded);
setState(() {
});
},
dividerColor: Colors.black,
expandedHeaderPadding: EdgeInsets.zero,
children: _childrenForExpansionPanel,
);
}
ExpansionPanel _expansionPanel(ExpansionPanelModel model){
return ExpansionPanel(
headerBuilder: (context, boolValue){
return Container(
height: 80,
alignment: Alignment.centerLeft,
child: Text("${model.title}"),
);
},
isExpanded: model.isExpanded,
canTapOnHeader: true,
body: Container(
height: 200,
color: Colors.red,
),
);
}
ExpansionPanelList _expansionPanelListRadio(){
_initChildrenForExpansionPanelRadio();
return ExpansionPanelList.radio(
expansionCallback: (index, isExpand){
_models[index].isExpanded = !_models[index].isExpanded;
print(_models[index].isExpanded);
setState(() {
});
},
dividerColor: Colors.black,
expandedHeaderPadding: EdgeInsets.zero,
children: _childrenForExpansionPanelRadio,
);
}
ExpansionPanelRadio _expansionPanelRadio(ExpansionPanelModel model){
return ExpansionPanelRadio(
value: model.value,
headerBuilder: (context, boolValue){
return Container(
height: 80,
alignment: Alignment.centerLeft,
child: Text("${model.title}"),
);
},
canTapOnHeader: true,
body: Container(
height: 200,
color: Colors.red,
),
);
}
}
class ExpansionPanelModel {
var value;
String title;
bool isExpanded;
ExpansionPanelModel(this.value, this.title, this.isExpanded);
}
4.2 ExpansionPanelList 常見(jiàn)屬性效果
ExpansionPanelList _expansionPanelList(){
_initChildrenForExpansionPanel();
return ExpansionPanelList(
expansionCallback: (index, isExpand){
_models[index].isExpanded = !_models[index].isExpanded;
print(_models[index].isExpanded);
setState(() {
});
},
dividerColor: Colors.green,
expandedHeaderPadding: EdgeInsets.all(30),
children: _childrenForExpansionPanel,
);
}
我們?cè)O(shè)置 dividerColor 為 green央星。
我們?cè)O(shè)置 expandedHeaderPadding 為 EdgeInsets.all(30),可以看到展開(kāi)后 Header 的 Text 組件的位置做出了相應(yīng)改變惫东。
5. ExpansionPanelRadio莉给、ExpansionPanelList.radio 詳解
5.1 代碼實(shí)現(xiàn)
相比上方 ExpansionPanel、ExpansionPanelList 其實(shí)只是換一種實(shí)現(xiàn)方式廉沮,他們唯一的差別是使用 Radio 方式颓遏,可以為設(shè)置默認(rèn)展開(kāi)其中一個(gè) ExpansionPanelRadio。
import 'package:flutter/material.dart';
class FMExpansionPanelVC extends StatefulWidget{
@override
FMExpansionPanelState createState() => FMExpansionPanelState();
}
class FMExpansionPanelState extends State <FMExpansionPanelVC>{
List <ExpansionPanelModel> _models = [];
List <ExpansionPanel> _childrenForExpansionPanel = [];
List <ExpansionPanelRadio> _childrenForExpansionPanelRadio = [];
@override
void initState(){
super.initState();
_initData();
}
void _initData(){
_models.clear();
_models.add(ExpansionPanelModel("EP1", "Title EP1", false));
_models.add(ExpansionPanelModel("EP2", "Title EP2", false));
_models.add(ExpansionPanelModel("EP3", "Title EP3", false));
_models.add(ExpansionPanelModel("EP4", "Title EP4", false));
_models.add(ExpansionPanelModel("EP5", "Title EP5", false));
print("initDate");
}
void _initChildrenForExpansionPanel(){
_childrenForExpansionPanel.clear();
_models.forEach((model) {
_childrenForExpansionPanel.add(_expansionPanel(model));
});
}
void _initChildrenForExpansionPanelRadio(){
_childrenForExpansionPanelRadio.clear();
_models.forEach((model) {
_childrenForExpansionPanelRadio.add(_expansionPanelRadio(model));
});
print(_childrenForExpansionPanelRadio);
}
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: Text("ExpansionPanel"),
),
body: SingleChildScrollView(
// child: _expansionPanelList(),
child: _expansionPanelListRadio(),
),
);
}
ExpansionPanelList _expansionPanelList(){
_initChildrenForExpansionPanel();
return ExpansionPanelList(
expansionCallback: (index, isExpand){
_models[index].isExpanded = !_models[index].isExpanded;
print(_models[index].isExpanded);
setState(() {
});
},
dividerColor: Colors.black,
expandedHeaderPadding: EdgeInsets.zero,
children: _childrenForExpansionPanel,
);
}
ExpansionPanel _expansionPanel(ExpansionPanelModel model){
return ExpansionPanel(
headerBuilder: (context, boolValue){
return Container(
height: 80,
alignment: Alignment.centerLeft,
child: Text("${model.title}"),
);
},
isExpanded: model.isExpanded,
canTapOnHeader: true,
body: Container(
height: 200,
color: Colors.red,
),
);
}
ExpansionPanelList _expansionPanelListRadio(){
_initChildrenForExpansionPanelRadio();
return ExpansionPanelList.radio(
expansionCallback: (index, isExpand){
_models[index].isExpanded = !_models[index].isExpanded;
print(_models[index].isExpanded);
setState(() {
});
},
dividerColor: Colors.black,
expandedHeaderPadding: EdgeInsets.zero,
children: _childrenForExpansionPanelRadio,
);
}
ExpansionPanelRadio _expansionPanelRadio(ExpansionPanelModel model){
return ExpansionPanelRadio(
value: model.value,
headerBuilder: (context, boolValue){
return Container(
height: 80,
alignment: Alignment.centerLeft,
child: Text("${model.title}"),
);
},
canTapOnHeader: true,
body: Container(
height: 200,
color: Colors.red,
),
);
}
}
class ExpansionPanelModel {
var value;
String title;
bool isExpanded;
ExpansionPanelModel(this.value, this.title, this.isExpanded){
}
}
5.2 設(shè)置默認(rèn)展開(kāi) ExpansionPanelRadio
它的原理其實(shí)很簡(jiǎn)單滞时,設(shè)置 ExpansionPanelRadio.value州泊,可以是字符串,也可以是數(shù)字漂洋,作為唯一識(shí)別標(biāo)識(shí)。注意每個(gè) value 不可以重復(fù)力喷,否則會(huì)報(bào)錯(cuò)刽漂。
All ExpansionPanelRadio identifier values must be unique.
'package:flutter/src/material/expansion_panel.dart':
Failed assertion: line 385 pos 14: '_allIdentifiersUnique()'
我們對(duì)示例代碼進(jìn)行以下改動(dòng),然后重新進(jìn)入頁(yè)面弟孟,此處熱重載不會(huì)更新頁(yè)面贝咙。
ExpansionPanelList _expansionPanelListRadio(){
_initChildrenForExpansionPanelRadio();
return ExpansionPanelList.radio(
expansionCallback: (index, isExpand){
_models[index].isExpanded = !_models[index].isExpanded;
setState(() {
});
},
initialOpenPanelValue: _models[2].value,
dividerColor: Colors.black,
expandedHeaderPadding: EdgeInsets.zero,
children: _childrenForExpansionPanelRadio,
);
}
6. 技術(shù)小結(jié)
- 注意 ExpansionPanel 不可以直接作為子控件給到 body,否則會(huì)報(bào)錯(cuò)拂募,這里用了 SingleChildScrollView 作為外層容器庭猩,使用 Column窟她、ListView...等很多控件都可以。
- 注意使用 ExpansionPanelList() 與 ExpansionPanelList.radio() 創(chuàng)建出來(lái)的 Widget蔼水,他們的 children 分別對(duì)應(yīng) <ExpansionPanel>震糖,<ExpansionPanelRadio>,此處容易報(bào)錯(cuò)趴腋。
- 注意 ExpansionPanelRadio.value 不可以相同吊说,容易報(bào)錯(cuò)。