浏览代码

VCheckBoxButtonGroup&VCheckBoxButton

Melon 1 年之前
父节点
当前提交
64291b7637
共有 1 个文件被更改,包括 158 次插入0 次删除
  1. 158 0
      lib/components/checkbox_button.dart

+ 158 - 0
lib/components/checkbox_button.dart

@@ -0,0 +1,158 @@
+import 'package:flutter/material.dart';
+
+/// 按钮式多选框组
+class VCheckBoxButtonGroup<T, TValue> extends StatefulWidget {
+  final List<T> source;
+  final List<TValue>? values;
+  final String Function(T data) labelGetter;
+  final TValue Function(T data) valueGetter;
+  final ValueChanged<List<TValue>>? onChanged;
+  final double? itemWidth;
+
+  const VCheckBoxButtonGroup({
+    super.key,
+    required this.source,
+    this.values,
+    required this.labelGetter,
+    required this.valueGetter,
+    this.onChanged,
+    this.itemWidth,
+  });
+
+  @override
+  State<StatefulWidget> createState() => _VCheckBoxGroupState<T, TValue>();
+}
+
+class _VCheckBoxGroupState<T, TValue>
+    extends State<VCheckBoxButtonGroup<T, TValue>> {
+  late List<TValue> _checkedValues;
+
+  @override
+  void initState() {
+    _checkedValues = widget.values ?? [];
+    super.initState();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    final children = <Widget>[];
+    final length = widget.source.length;
+    for (var i = 0; i < length; i++) {
+      final e = widget.source[i];
+      children.add(
+        SizedBox(
+          width: widget.itemWidth ?? 160,
+          child: VCheckBoxButton(
+            label: widget.labelGetter(e),
+            isChecked: false,
+            onChanged: (value) {
+              _onItemChanged(e, value);
+            },
+          ),
+        ),
+      );
+    }
+    return Wrap(
+      spacing: 12,
+      runSpacing: 8,
+      children: children,
+    );
+  }
+
+  void _onItemChanged(T data, bool isChecked) {
+    final value = widget.valueGetter(data);
+    if (isChecked) {
+      if (_checkedValues.contains(value) == false) {
+        _checkedValues.add(value);
+      }
+    } else {
+      _checkedValues.remove(value);
+    }
+    widget.onChanged?.call(_checkedValues);
+  }
+}
+
+/// 按钮式多选框
+class VCheckBoxButton extends StatefulWidget {
+  /// 文本
+  final String label;
+
+  /// 是否默认选中
+  final bool? isChecked;
+
+  /// 选中状态变更
+  final ValueChanged<bool>? onChanged;
+
+  const VCheckBoxButton({
+    super.key,
+    required this.label,
+    this.isChecked,
+    this.onChanged,
+  });
+  @override
+  State<StatefulWidget> createState() => _VCheckBoxState();
+}
+
+class _VCheckBoxState extends State<VCheckBoxButton> {
+  bool _isChecked = false;
+
+  @override
+  void initState() {
+    if (widget.isChecked != null) {
+      _isChecked = widget.isChecked!;
+    }
+    super.initState();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    const height = 56.0;
+    const borderRadius = height / 2;
+    final primaryColor = Theme.of(context).primaryColor;
+    return Material(
+      child: Ink(
+        child: InkWell(
+          borderRadius: BorderRadius.circular(borderRadius),
+          onTap: () {
+            setState(() {
+              _isChecked = !_isChecked;
+              widget.onChanged?.call(_isChecked);
+            });
+          },
+          child: Container(
+            padding: const EdgeInsets.only(left: 0, right: borderRadius),
+            alignment: Alignment.center,
+            height: height,
+            decoration: BoxDecoration(
+              color: _isChecked ? primaryColor : Colors.grey.shade200,
+              borderRadius: BorderRadius.circular(borderRadius),
+              border: _isChecked ? null : Border.all(color: primaryColor),
+            ),
+            child: Row(
+              mainAxisSize: MainAxisSize.min,
+              crossAxisAlignment: CrossAxisAlignment.center,
+              children: [
+                if (_isChecked) ...[
+                  const Icon(
+                    Icons.check_rounded,
+                    color: Colors.green,
+                    size: 24,
+                  ),
+                  const SizedBox(width: 8),
+                ],
+                if (!_isChecked) const SizedBox(width: 32),
+                Text(
+                  widget.label,
+                  style: TextStyle(
+                    color: _isChecked ? Colors.white : primaryColor,
+                    fontSize: 20,
+                  ),
+                ),
+              ],
+            ),
+          ),
+        ),
+      ),
+    );
+  }
+}