Wigets学习之Cell(自实现)

作者:renzp94
时间:2021-07-01 02:46:41

Flutter没有Cell(单元格)部件,所以接下来自实现两个部件:CellGroupCell

cell.dart

import 'package:flutter/material.dart';

// 数据共享
class _Provider extends InheritedWidget {
  _Provider({required Widget child, required this.data}) : super(child: child);

  final dynamic data;

  static of(BuildContext context) {
    return context.getElementForInheritedWidgetOfExactType<_Provider>()?.widget;
  }

  @override
  bool updateShouldNotify(covariant InheritedWidget oldWidget) => false;
}

class CellGroup extends StatelessWidget {
  const CellGroup(
      {Key? key, required this.children, this.title, this.isBorder = true})
      : super(key: key);

  // 单元格列表
  final List<Cell> children;
  // 单元格组标题
  final String? title;
  // 单元格是否显示底部边框
  final bool? isBorder;

  @override
  Widget build(BuildContext context) {
    final List<Widget> list = [];

    if (title != null) {
      list.add(Padding(
        padding: EdgeInsets.symmetric(vertical: 8),
        child: Text(
          title!,
          style: TextStyle(color: Colors.black26),
        ),
      ));
    }

    list.addAll(children);

    return _Provider(
      data: {
        'isBorder': isBorder,
      },
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: list,
      ),
    );
  }
}

const defaultRightIcon = const Icon(
  Icons.arrow_forward_ios,
  color: Colors.black26,
  size: 20,
);

class Cell extends StatelessWidget {
  const Cell(
      {Key? key,
      this.icon,
      required this.title,
      this.subTitle,
      this.rightIcon = defaultRightIcon,
      this.color = Colors.white,
      this.titleColor = Colors.black,
      this.titleStyle,
      this.subTitleColor = Colors.black26,
      this.subTitleStyle,
      this.height = 48,
      this.horizontalPadding = 12,
      this.isBorder})
      : super(key: key);

  // 左侧图标
  final Widget? icon;
  // 标题
  final String title;
  // 副标题
  final String? subTitle;
  // 右侧图标,默认为右箭头
  final Icon? rightIcon;
  // 背景色
  final Color? color;
  // 标题颜色
  final Color? titleColor;
  // 标题样式
  final TextStyle? titleStyle;
  // 副标题颜色
  final Color? subTitleColor;
  // 副标题样式
  final TextStyle? subTitleStyle;
  // 高度
  final double? height;
  // 两侧边距
  final double? horizontalPadding;
  // 是否显示border
  final bool? isBorder;

  @override
  Widget build(BuildContext context) {
    final List<Widget> list = [];
    if (icon != null) {
      list.add(icon!);
    }

    final Text titleWidget = Text(
      title,
      maxLines: 1,
      overflow: TextOverflow.ellipsis,
      style: titleStyle != null ? titleStyle : TextStyle(color: titleColor),
    );

    final List<Widget> titleList = [titleWidget];

    if (subTitle != null) {
      titleList.add(Text(
        subTitle!,
        style: subTitleStyle != null
            ? subTitleStyle
            : TextStyle(color: subTitleColor),
        overflow: TextOverflow.ellipsis,
      ));
    }

    list.add(Expanded(
      child: Container(
        padding: EdgeInsets.only(left: 8),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: titleList,
        ),
      ),
    ));

    list.add(rightIcon!);

    dynamic provider = _Provider?.of(context);
    // isBorder存在则使用isBorder,否则判断CellGroup.isBorder存在,则用CellGroup.isBorder,否则为true
    bool borderVisible = isBorder ?? provider?.data['isBorder'] ?? true;

    return Container(
      height: height! < 48 ? 48 : height,
      decoration: borderVisible
          ? BoxDecoration(
              color: color,
              border: Border(bottom: BorderSide(color: Colors.black12)))
          : null,
      padding: EdgeInsets.symmetric(horizontal: horizontalPadding!),
      child: Row(
        children: list,
      ),
    );
  }
}

CellGroup

单元格组,用于包裹单元格

  • children:单元格列表(必填),类型是List<Cell>
  • title:单元格组标题
  • isBorder:单元格是否显示底部边框

Cell

  • icon:左侧图标
  • title:标题
  • subTitle:副标题
  • rightIcon:右侧图标,默认为Icons.arrow_forward_ios
  • color:背景色
  • titleColor:标题颜色
  • titleStyle:标题样式
  • subTitleColor:副标题颜色
  • subTitleStyle:副标题样式
  • height:高度,默认为 48 且最小为 48
  • horizontalPadding:两侧边距,默认为 12
  • isBorder:是否显示底部边框
import 'package:flutter/material.dart';
import 'package:learn/widgets/cell.dart';

void main() {
  runApp(App());
}

class App extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: '自实现Cell',
      home: Scaffold(
        appBar: AppBar(
          title: Text('自实现Cell'),
        ),
        body: Padding(
          padding: EdgeInsets.all(12),
          child: CellGroup(
            title: '标题',
            children: [
              Cell(
                icon: Icon(Icons.mail),
                title: '邮件',
              ),
              Cell(
                icon: Icon(Icons.message),
                title: '消息通知',
              )
            ],
          ),
        ),
      ),
    );
  }
}