Flutter 实战

Flutter入门(36):Flutter 组件之 Expans

2020-10-14  本文已影响0人  Maojunhao

1. 基本介绍

ExpansionPanel、ExpansionPanelRadio 是一种常见的折叠框。
ExpansionPanelList 是承载折叠框的一个父类控件。

2. 示例代码

代码下载地址。如果对你有帮助的话记得给个关注,代码会根据我的 Flutter 专题不断更新。

3. 属性介绍

ExpansionPanel 属性 介绍
headerBuilder @required,Header Widget 构造方法
body @required,展开部分 Widget
isExpanded 是否展开,默认为 false
canTapOnHeader 是否可以点击 header 用来展开收起,false
ExpansionPanelRadio属性 介绍
value @required 唯一标识
headerBuilder @required Header Widget 构造方法
body @required,展开部分 Widget
canTapOnHeader 是否可以点击 header 用来展开收起,false
ExpansionPanelList属性 介绍
children 子控件数组,类型为 <ExpansionPanel> 的数组
expansionCallback 点击折叠收起回调函数,(index, isExpand){},返回当前下标以及是否折叠
animationDuration 动画时间,默认为 kThemeAnimationDuration
expandedHeaderPadding 展开后 Header 的 padding,默认为 _kPanelHeaderExpandedDefaultPadding
dividerColor 分割线颜色

ExpansionPanelList.radio 属性 | 介绍
children | 子控件数组,类型为 <ExpansionPanelRadio> 的数组
expansionCallback | 点击折叠收起回调函数,(index, isExpand){},返回当前下标以及是否折叠
initialOpenPanelValue | 当前选中标识,initialOpenPanelValue == ExpansionPanelRadio.value 时,该 ExpansionPanelRadio 会默认展开
animationDuration | 动画时间,默认为 kThemeAnimationDuration
expandedHeaderPadding | 展开后 Header 的 padding,默认为 _kPanelHeaderExpandedDefaultPadding
dividerColor | 分割线颜色

4. ExpansionPanel,ExpansionPanelList 详解

4.1 代码实现

ExpansionPanel 是单个折叠框,他的效果实现还需要依托于 ExpansionPanelList,这边直接上 demo,一个简单的折叠框的实现。

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 常见属性效果

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

我们设置 dividerColor 为 green。

dividerColor.png

我们设置 expandedHeaderPadding 为 EdgeInsets.all(30),可以看到展开后 Header 的 Text 组件的位置做出了相应改变。

expandedHeaderPadding.png

5. ExpansionPanelRadio、ExpansionPanelList.radio 详解

5.1 代码实现

相比上方 ExpansionPanel、ExpansionPanelList 其实只是换一种实现方式,他们唯一的差别是使用 Radio 方式,可以为设置默认展开其中一个 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 设置默认展开 ExpansionPanelRadio

它的原理其实很简单,设置 ExpansionPanelRadio.value,可以是字符串,也可以是数字,作为唯一识别标识。注意每个 value 不可以重复,否则会报错。

All ExpansionPanelRadio identifier values must be unique.
'package:flutter/src/material/expansion_panel.dart':
Failed assertion: line 385 pos 14: '_allIdentifiersUnique()'

我们对示例代码进行以下改动,然后重新进入页面,此处热重载不会更新页面。

  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. 技术小结

上一篇下一篇

猜你喜欢

热点阅读