flutter 自定义简单好用的小组件(一)

101 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第7天,点击查看活动详情

蚂蚁线的实现

image.png

思路

  • 一个个实线均匀的分布在一个方向上,可以使用list生成一下
  • 外层使用LayoutBuilder,获取平铺方向上的约束条件。
  • 设置参数,接收外部传入的高度、方向、颜色
  • 设置实体的宽度,动态计算,平铺方向上实体的个数

代码实现

import 'package:flutter/material.dart';
class DotLine extends StatelessWidget {
  final double height;
  final Color color;
  final Axis direction;

  const DotLine(
      {this.height = 1,
      this.color = Colors.black,
      this.direction = Axis.horizontal});

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
        builder: (BuildContext context, BoxConstraints constraints) {
      final boxWidth = direction == Axis.horizontal
          ? constraints.constrainWidth()
          : constraints.constrainHeight();
      final dashWidth = 5.0;
      final dashHeight = height;
      final dashCount = (boxWidth / (2 * dashWidth)).floor();
      return Flex(direction: direction,
       mainAxisAlignment: MainAxisAlignment.spaceAround,
       children: 
        List.generate(dashCount, (_){
          return SizedBox(
            width:direction == Axis.horizontal ? dashWidth : dashHeight,
            height: direction == Axis.horizontal ? dashHeight : dashWidth,
            child: DecoratedBox(decoration: BoxDecoration(color: color),)
          );
        })
      );
    });
  }
}

使用方法

Padding(
  padding: EdgeInsets.symmetric(vertical: 20.w),
  child: DotLine(
    color: Colors.grey,
  ),
)

限制输入框只能输入小数点后2位

思路

  • TextFieldinputFormatters进行扩展,首先键盘类型是数字的,可以输入小数的类型
  • 设置键盘类型,增加约束

键盘类型

keyboardType: TextInputType.numberWithOptions(
    decimal: true),

inputFormatters类扩展

import 'package:flutter/services.dart';

// 价格输入 小数点后两位
class UsNumberTextInputFormatter extends TextInputFormatter {
  late RegExp regExp;
  UsNumberTextInputFormatter({int digitsCount = 2}) {
    String string =
        r'^(([0])|([1-9][0-9]*)|(([0]\.\d{0,count}|[1-9][0-9]*\.\d{0,count})))$';
    string = string.replaceAll(RegExp(r'count'), '$digitsCount');
    regExp = RegExp(string);
  }
  @override
  TextEditingValue formatEditUpdate(
      TextEditingValue oldValue, TextEditingValue newValue) {
    return oldValue.text.length > newValue.text.length ||
            regExp.hasMatch(newValue.text)
        ? newValue
        : oldValue;
  }
}

可根据需要传入参数digitsCount,决定输入小数点后的位数

使用方法:

//小数后2位
inputFormatters: [UsNumberTextInputFormatter()],

checkbox 可圆可方

自定义checkbox 实现,点击选中,checkbox 可圆可方。

思路

  • 一个Icon+Text文本放在一行Row,为了好看套层padding,显的有格局
  • 支持设置选择颜色和未选择颜色
  • 想要可以被点击,加层GestureDetector
  • 为了显示中心位置,可加层center,看需要。
  • 可圆可方就是可甜可咸有的换,根据外部传入的参数,决定显示圆的还是方的
  • 反显数据的时候,支持disabled,又多了个技能点
  • 不想显示文本text的时候,直接来个widget child,想要展示什么就展示什么
  • 根据自己的需求,加更多的可传参

代码实现

import 'package:flutter/material.dart';

class CheckBox extends StatefulWidget {
  final bool value;
  // 不可选
  final bool disabled;
  final Function(bool)? onChanged;
  final EdgeInsetsGeometry? padding;
  final Color? selectColor;
  final String? title;
  // 选择图标的大小
  final double? size;
  /// 选择框的类型 r (round) 圆  s (square) 方的
  final String type;
  final Widget? child;
  CheckBox(
      {Key? key,
      required this.value,
      this.onChanged,
      this.padding,
      this.title,
      this.child,
      this.type = 's',
      this.selectColor,
      this.size,
      this.disabled = false})
      : super(key: key);

  @override
  State<CheckBox> createState() => _CheckBoxState();
}

class _CheckBoxState extends State<CheckBox> {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: GestureDetector(
          onTap: () {
            if (widget.disabled == false) {
              widget.onChanged?.call(!widget.value);
            }
          },
          child: Row(
            children: [
              Padding(
                padding: widget.padding ?? const EdgeInsets.all(3.0),
                child: widget.disabled
                    ? Icon(
                        widget.type == 's'
                            ? Icons.check_box_outline_blank
                            : Icons.do_not_disturb_alt,
                        size: widget.size ?? 20.0,
                        color: Color(0xfff5f5f5),
                      )
                    : (widget.value
                        ? Icon(
                            widget.type == 's'
                                ? Icons.check_box
                                : Icons.check_circle,
                            size: widget.size ?? 20.0,
                            color: widget.selectColor ?? Color(0xfffe3536),
                          )
                        : Icon(
                            // Icons.panorama_fish_eye,
                            widget.type == 's'
                                ? Icons.check_box_outline_blank
                                : Icons.radio_button_unchecked,
                            size: widget.size ?? 20.0,
                            color: Color(0xffEEEEEE),
                          )),
              ),
              widget.child != null
                  ? widget.child!
                  : Text(
                      '${widget.title ?? ''}',
                      style: TextStyle(fontSize: 15),
                    )
            ],
          )),
    );
  }
}

使用方法

CheckBoxYF(
    value: true,
    child: Text(
      '阅读并同意《XXXXX》',
      style: TextStyle(fontSize: 16),
    ),
    onChanged: (bool val) {},
  ),