Flutter入門(mén)(36):Flutter 組件之 ExpansionPanel是趴、ExpansionPanelRadio、ExpansionPanelList 詳解

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);
}
ExpansionPanel normal.gif

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央星。

dividerColor.png

我們?cè)O(shè)置 expandedHeaderPadding 為 EdgeInsets.all(30),可以看到展開(kāi)后 Header 的 Text 組件的位置做出了相應(yīng)改變惫东。

expandedHeaderPadding.png

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){

  }
}
ExpansionPanel radio.gif

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,
    );
  }
ExpansionPanelRadio initialOpenPanelValue.png

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ò)。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末优炬,一起剝皮案震驚了整個(gè)濱河市颁井,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蠢护,老刑警劉巖雅宾,帶你破解...
    沈念sama閱讀 211,290評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異葵硕,居然都是意外死亡眉抬,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門(mén)贬芥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)吐辙,“玉大人,你說(shuō)我怎么就攤上這事蘸劈』杷眨” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,872評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵威沫,是天一觀的道長(zhǎng)贤惯。 經(jīng)常有香客問(wèn)我,道長(zhǎng)棒掠,這世上最難降的妖魔是什么孵构? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,415評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮烟很,結(jié)果婚禮上颈墅,老公的妹妹穿的比我還像新娘。我一直安慰自己雾袱,他們只是感情好恤筛,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,453評(píng)論 6 385
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著芹橡,像睡著了一般毒坛。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,784評(píng)論 1 290
  • 那天煎殷,我揣著相機(jī)與錄音屯伞,去河邊找鬼。 笑死豪直,一個(gè)胖子當(dāng)著我的面吹牛劣摇,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播顶伞,決...
    沈念sama閱讀 38,927評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼饵撑,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了唆貌?” 一聲冷哼從身側(cè)響起滑潘,我...
    開(kāi)封第一講書(shū)人閱讀 37,691評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎锨咙,沒(méi)想到半個(gè)月后语卤,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,137評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡酪刀,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,472評(píng)論 2 326
  • 正文 我和宋清朗相戀三年粹舵,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片骂倘。...
    茶點(diǎn)故事閱讀 38,622評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡眼滤,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出历涝,到底是詐尸還是另有隱情诅需,我是刑警寧澤,帶...
    沈念sama閱讀 34,289評(píng)論 4 329
  • 正文 年R本政府宣布荧库,位于F島的核電站堰塌,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏分衫。R本人自食惡果不足惜场刑,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,887評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蚪战。 院中可真熱鬧牵现,春花似錦、人聲如沸邀桑。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,741評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)概漱。三九已至,卻和暖如春喜喂,著一層夾襖步出監(jiān)牢的瞬間瓤摧,已是汗流浹背竿裂。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留照弥,地道東北人腻异。 一個(gè)月前我還...
    沈念sama閱讀 46,316評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像这揣,于是被迫代替她去往敵國(guó)和親悔常。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,490評(píng)論 2 348