• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

Flutter自定义折叠组件

武飞扬头像
Laoski
帮助1

一、基础组件

  1.  
    import 'package:flutter/material.dart';
  2.  
     
  3.  
    const Duration _kExpand = Duration(milliseconds: 200);
  4.  
     
  5.  
    /* 折叠组件 */
  6.  
    class ExpansionCustom extends StatefulWidget {
  7.  
    const ExpansionCustom({
  8.  
    Key key,
  9.  
    this.title,
  10.  
    this.onExpansionChanged,
  11.  
    this.children = const <Widget>[],
  12.  
    this.initiallyExpanded = false,
  13.  
    this.isExpanded,
  14.  
    this.padding,
  15.  
    }) : assert(initiallyExpanded != null),
  16.  
    super(key: key);
  17.  
     
  18.  
    final Widget title;
  19.  
    final ValueChanged<bool> onExpansionChanged;
  20.  
    final List<Widget> children;
  21.  
    final bool initiallyExpanded;
  22.  
    final bool isExpanded;
  23.  
    final EdgeInsetsGeometry padding;
  24.  
     
  25.  
    @override
  26.  
    _ExpansionCustomState createState() => _ExpansionCustomState();
  27.  
    }
  28.  
     
  29.  
    class _ExpansionCustomState extends State<ExpansionCustom>
  30.  
    with SingleTickerProviderStateMixin {
  31.  
    static final Animatable<double> _easeInTween =
  32.  
    CurveTween(curve: Curves.easeIn);
  33.  
     
  34.  
    AnimationController _controller;
  35.  
    Animation<double> _heightFactor;
  36.  
     
  37.  
    bool _isExpanded = false;
  38.  
     
  39.  
    @override
  40.  
    void initState() {
  41.  
    super.initState();
  42.  
    _controller = AnimationController(duration: _kExpand, vsync: this);
  43.  
    _heightFactor = _controller.drive(_easeInTween);
  44.  
     
  45.  
    _isExpanded =
  46.  
    PageStorage.of(context)?.readState(context) ?? widget.initiallyExpanded;
  47.  
    if (_isExpanded) _controller.value = 1.0;
  48.  
    }
  49.  
     
  50.  
    diyHandle() {
  51.  
    if (widget.isExpanded != null) {
  52.  
    setState(() {
  53.  
    if (widget.isExpanded) {
  54.  
    _controller.forward();
  55.  
    } else {
  56.  
    _controller.reverse().then<void>((void value) {
  57.  
    if (!mounted) return;
  58.  
    setState(() {});
  59.  
    });
  60.  
    }
  61.  
    });
  62.  
    }
  63.  
    }
  64.  
     
  65.  
    @override
  66.  
    void dispose() {
  67.  
    _controller.dispose();
  68.  
    super.dispose();
  69.  
    }
  70.  
     
  71.  
    void _handleTap() {
  72.  
    setState(() {
  73.  
    _isExpanded = !_isExpanded;
  74.  
    if (_isExpanded) {
  75.  
    _controller.forward();
  76.  
    } else {
  77.  
    _controller.reverse().then<void>((void value) {
  78.  
    if (!mounted) return;
  79.  
    setState(() {});
  80.  
    });
  81.  
    }
  82.  
    PageStorage.of(context)?.writeState(context, _isExpanded);
  83.  
    });
  84.  
    if (widget.onExpansionChanged != null)
  85.  
    widget.onExpansionChanged(_isExpanded);
  86.  
    }
  87.  
     
  88.  
    Widget _buildChildren(BuildContext context, Widget child) {
  89.  
    return Container(
  90.  
    child: Column(
  91.  
    mainAxisSize: MainAxisSize.min,
  92.  
    children: <Widget>[
  93.  
    GestureDetector(
  94.  
    onTap: _handleTap,
  95.  
    child: Container(
  96.  
    color: Colors.transparent,
  97.  
    width: double.infinity,
  98.  
    padding: widget.padding ?? EdgeInsets.only(left: 10, right: 10),
  99.  
    child: widget.title ?? Container(),
  100.  
    ),
  101.  
    ),
  102.  
    ClipRect(
  103.  
    child: Align(
  104.  
    heightFactor: _heightFactor.value,
  105.  
    child: child,
  106.  
    ),
  107.  
    ),
  108.  
    ],
  109.  
    ),
  110.  
    );
  111.  
    }
  112.  
     
  113.  
    @override
  114.  
    Widget build(BuildContext context) {
  115.  
    diyHandle();
  116.  
    final bool closed = !_isExpanded && _controller.isDismissed;
  117.  
    return AnimatedBuilder(
  118.  
    animation: _controller.view,
  119.  
    builder: _buildChildren,
  120.  
    child: closed ? null : Column(children: widget.children),
  121.  
    );
  122.  
    }
  123.  
    }
学新通

二、拓展组件

对基础组件加以封装,可以实现更多功能的拓展组件,本文以折叠卡片和折叠信息为例。

折叠卡片

  1.  
    import 'package:flutter/material.dart';
  2.  
    import './expansion_custom.dart';
  3.  
     
  4.  
    /* 折叠卡片 */
  5.  
    class ExpansionCard extends StatefulWidget {
  6.  
    final EdgeInsets margin; // 外边距
  7.  
    final Decoration cardDecoration; // 卡片样式
  8.  
    final Function onTap; // 点击标题的回调
  9.  
    final String tlText; // 左侧标题
  10.  
    final TextStyle tlStyle;
  11.  
    final Widget tlWidget;
  12.  
    final String trText; // 右侧标题
  13.  
    final TextStyle trStyle;
  14.  
    final Widget trWidget;
  15.  
    final List<Widget> contentWidget; // 折叠内容
  16.  
     
  17.  
    ExpansionCard({
  18.  
    Key key,
  19.  
    this.margin,
  20.  
    this.cardDecoration,
  21.  
    this.onTap,
  22.  
    this.tlText,
  23.  
    this.tlStyle,
  24.  
    this.tlWidget,
  25.  
    this.trText,
  26.  
    this.trStyle,
  27.  
    this.trWidget,
  28.  
    this.contentWidget,
  29.  
    }) : super(key: key);
  30.  
     
  31.  
    @override
  32.  
    _ExpansionCardState createState() => _ExpansionCardState();
  33.  
    }
  34.  
     
  35.  
    class _ExpansionCardState extends State<ExpansionCard> {
  36.  
    bool _isExpanded = false;
  37.  
     
  38.  
    @override
  39.  
    Widget build(BuildContext context) {
  40.  
    return Container(
  41.  
    margin: widget.margin ?? EdgeInsets.all(10),
  42.  
    padding: EdgeInsets.all(10),
  43.  
    decoration: widget.cardDecoration ??
  44.  
    BoxDecoration(
  45.  
    color: Colors.white,
  46.  
    borderRadius: BorderRadius.all(Radius.circular(10)),
  47.  
    ),
  48.  
    child: Column(
  49.  
    children: <Widget>[
  50.  
    GestureDetector(
  51.  
    onTap: () {
  52.  
    this._isExpanded = !this._isExpanded;
  53.  
    if (mounted) {
  54.  
    setState(() {});
  55.  
    }
  56.  
     
  57.  
    if (widget.onTap != null) {
  58.  
    widget.onTap(this._isExpanded);
  59.  
    }
  60.  
    },
  61.  
    child: Container(
  62.  
    color: Colors.transparent,
  63.  
    child: Row(
  64.  
    mainAxisAlignment: MainAxisAlignment.spaceBetween,
  65.  
    children: <Widget>[
  66.  
    widget.tlWidget ??
  67.  
    Text(
  68.  
    '${widget.tlText ?? ""}',
  69.  
    style: widget.tlStyle ??
  70.  
    TextStyle(
  71.  
    fontSize: 16, fontWeight: FontWeight.bold),
  72.  
    ),
  73.  
    Row(
  74.  
    children: <Widget>[
  75.  
    widget.trWidget ??
  76.  
    Text('${widget.trText ?? ""}',
  77.  
    style: widget.trStyle ??
  78.  
    TextStyle(
  79.  
    fontSize: 16,
  80.  
    fontWeight: FontWeight.bold)),
  81.  
    SizedBox(width: 4),
  82.  
    Icon(
  83.  
    this._isExpanded ? Icons.remove : Icons.add,
  84.  
    color: Colors.black,
  85.  
    size: 18,
  86.  
    ),
  87.  
    ],
  88.  
    )
  89.  
    ],
  90.  
    ),
  91.  
    ),
  92.  
    ),
  93.  
    ExpansionCustom(
  94.  
    children: <Widget>[
  95.  
    Divider(height: 10),
  96.  
    Column(
  97.  
    children: widget.contentWidget ?? [Container()],
  98.  
    )
  99.  
    ],
  100.  
    initiallyExpanded: false,
  101.  
    isExpanded: this._isExpanded,
  102.  
    )
  103.  
    ],
  104.  
    ),
  105.  
    );
  106.  
    }
  107.  
    }
学新通

折叠信息

  1.  
    import 'package:flutter/material.dart';
  2.  
    import './expansion_custom.dart';
  3.  
     
  4.  
    /* 折叠消息 */
  5.  
    class ExpansionMsg extends StatefulWidget {
  6.  
    final double width; //宽
  7.  
    final Color bgColor; //背景颜色
  8.  
    final Widget icon;//左侧icon
  9.  
    final String msgText; //文字提示
  10.  
    final TextStyle msgTextStyle; //文字提示样式
  11.  
    final Function onClose; //点击关闭时的回调
  12.  
    ExpansionMsg(
  13.  
    {Key key,
  14.  
    this.width,
  15.  
    this.bgColor,
  16.  
    this.icon,
  17.  
    this.msgText,
  18.  
    this.msgTextStyle,
  19.  
    this.onClose})
  20.  
    : super(key: key);
  21.  
     
  22.  
    @override
  23.  
    _ExpansionMsgState createState() => _ExpansionMsgState();
  24.  
    }
  25.  
     
  26.  
    class _ExpansionMsgState extends State<ExpansionMsg> {
  27.  
    bool _showContent = true;
  28.  
     
  29.  
    @override
  30.  
    Widget build(BuildContext context) {
  31.  
    return ExpansionCustom(
  32.  
    title: Container(),
  33.  
    initiallyExpanded: true, //默认是否展开
  34.  
    isExpanded: this._showContent,
  35.  
    children: <Widget>[
  36.  
    MessageBox(
  37.  
    width: widget.width,
  38.  
    bgColor: widget.bgColor,
  39.  
    msgTextStyle: widget.msgTextStyle,
  40.  
    msgText: widget.msgText,
  41.  
    canClose: true,
  42.  
    onClose: () {
  43.  
    this._showContent = false;
  44.  
     
  45.  
    if (mounted) {
  46.  
    setState(() {});
  47.  
    }
  48.  
     
  49.  
    if (widget.onClose != null) {
  50.  
    widget.onClose();
  51.  
    }
  52.  
    },
  53.  
    ),
  54.  
    ],
  55.  
    );
  56.  
    }
  57.  
    }
  58.  
     
  59.  
    /* 消息盒子 */
  60.  
    class MessageBox extends StatelessWidget {
  61.  
    final double width;
  62.  
    final Color bgColor;
  63.  
    final Widget icon;
  64.  
    final String msgText;
  65.  
    final TextStyle msgTextStyle;
  66.  
    final Function onClose;
  67.  
    final bool canClose;
  68.  
    const MessageBox(
  69.  
    {Key key,
  70.  
    this.width,
  71.  
    this.bgColor,
  72.  
    this.icon,
  73.  
    this.msgText,
  74.  
    this.msgTextStyle,
  75.  
    this.onClose,
  76.  
    this.canClose = true})
  77.  
    : super(key: key);
  78.  
     
  79.  
    @override
  80.  
    Widget build(BuildContext context) {
  81.  
    return Container(
  82.  
    padding: EdgeInsets.only(
  83.  
    top: 6,
  84.  
    bottom: 6,
  85.  
    left: 10,
  86.  
    right: 10,
  87.  
    ),
  88.  
    width: width ?? double.infinity,
  89.  
    color: bgColor ?? Color.fromRGBO(253, 246, 236, 1),
  90.  
    child: Row(
  91.  
    crossAxisAlignment: CrossAxisAlignment.start,
  92.  
    children: <Widget>[
  93.  
    Container(
  94.  
    width: 20,
  95.  
    margin: EdgeInsets.only(right: 10),
  96.  
    child: icon ??
  97.  
    Icon(Icons.warning,
  98.  
    size: 20, color: Color.fromRGBO(230, 162, 60, 1)),
  99.  
    ),
  100.  
    Expanded(
  101.  
    child: Container(
  102.  
    child: Text(
  103.  
    msgText ??
  104.  
    '这是一条消息提示',
  105.  
    style: msgTextStyle ??
  106.  
    TextStyle(
  107.  
    fontSize: 12, color: Color.fromRGBO(230, 162, 60, 1)),
  108.  
    ),
  109.  
    )),
  110.  
    canClose
  111.  
    ? GestureDetector(
  112.  
    onTap: onClose,
  113.  
    child: Container(
  114.  
    color: Colors.transparent,
  115.  
    width: 20,
  116.  
    height: 20,
  117.  
    child: Icon(
  118.  
    Icons.close,
  119.  
    size: 20,
  120.  
    ),
  121.  
    ),
  122.  
    )
  123.  
    : Container(width: 20)
  124.  
    ],
  125.  
    ),
  126.  
    );
  127.  
    }
  128.  
    }
学新通

三、组件使用

  1.  
    import 'package:flutter/material.dart';
  2.  
    import '../../compontents/expansion/expansion_custom.dart';
  3.  
    import '../../compontents/expansion/expansion_card.dart';
  4.  
    import '../../compontents/expansion/expansion_msg.dart';
  5.  
     
  6.  
    /*组件演示*/
  7.  
    class Demo extends StatefulWidget {
  8.  
    Demo({Key key}) : super(key: key);
  9.  
     
  10.  
    @override
  11.  
    State<Demo> createState() => _DemoState();
  12.  
    }
  13.  
     
  14.  
    class _DemoState extends State<Demo> {
  15.  
    @override
  16.  
    Widget build(BuildContext context) {
  17.  
    return Scaffold(
  18.  
    appBar: AppBar(
  19.  
    title: Text('Demo'),
  20.  
    centerTitle: true,
  21.  
    ),
  22.  
    body: Container(
  23.  
    child: Wrap(
  24.  
    spacing: 20,
  25.  
    crossAxisAlignment: WrapCrossAlignment.center,
  26.  
    children: <Widget>[
  27.  
    SizedBox(height: 10),
  28.  
    ExpansionCustom(
  29.  
    title: Container(
  30.  
    child: Text('标题'), alignment: Alignment.centerLeft),
  31.  
    children: <Widget>[Text('内容1'), Text('内容2'), Text('内容3')],
  32.  
    ),
  33.  
    SizedBox(height: 10),
  34.  
    ExpansionCard(
  35.  
    tlText: '左侧标题',
  36.  
    trText: '右侧标题',
  37.  
    contentWidget: <Widget>[
  38.  
    Text('折叠内容1'),
  39.  
    Text('折叠内容2'),
  40.  
    Text('折叠内容3'),
  41.  
    Text('折叠内容4'),
  42.  
    Text('折叠内容5'),
  43.  
    ],
  44.  
    ),
  45.  
    SizedBox(height: 10),
  46.  
    ExpansionMsg(
  47.  
    msgText:
  48.  
    '这是一条消息提示这是一条消息提示这是一条消息提示这是一条消息提示这是一条消息提示这是一条消息提示这是一条消息提示这是一条消息提示这是一条消息提示这是一条消息提示这是一条消息提示这是一条消息提示'),
  49.  
    ]),
  50.  
    ));
  51.  
    }
  52.  
    }
学新通

四、效果演示

学新通

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgbkbeb
系列文章
更多 icon
同类精品
更多 icon
继续加载