| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223 |
- import 'package:flutter/material.dart';
- /// 数据转换函数签名
- /// 将原始数据转换为SelectOption类型的函数
- typedef SelectOptionConverter<T> = SelectOption Function(T data);
- /// 选择器选项数据模型
- class SelectOption {
- final String label;
- final String value;
- final dynamic extra;
- SelectOption({required this.label, required this.value, this.extra});
- }
- /// 通用选择器组件
- /// 支持静态数据源和动态API数据源
- class VberSelect<T> extends StatefulWidget {
- /// 静态数据列表
- final List<T>? items;
- /// API获取数据的方法
- final Future<List<T>> Function()? fetchData;
- /// 数据转换方法,将原始数据转换为SelectOption
- final SelectOptionConverter<T> converter;
- /// 当前选中的值
- final String? value;
- /// 值改变回调
- final Function(String?)? onChanged;
- /// 提示文字
- final String? hint;
- /// 是否启用
- final bool enabled;
- /// 是否显示"全部"选项
- final bool showAll;
- /// 是否隐藏下划线
- final bool hideUnderline;
- /// 是否显示清空按钮
- final bool showClearButton;
- const VberSelect({
- super.key,
- this.items,
- this.fetchData,
- required this.converter,
- this.value,
- this.onChanged,
- this.hint,
- this.enabled = true,
- this.showAll = false,
- this.hideUnderline = false,
- this.showClearButton = false,
- });
- @override
- State<VberSelect<T>> createState() => _VberSelectState<T>();
- }
- class _VberSelectState<T> extends State<VberSelect<T>> {
- List<T>? _items;
- bool _loading = false;
- String? _selectedValue;
- @override
- void initState() {
- super.initState();
- _selectedValue = widget.value;
- // 使用WidgetsBinding.instance.addPostFrameCallback确保在widget构建完成后再加载数据
- WidgetsBinding.instance.addPostFrameCallback((_) {
- _loadData();
- });
- }
- @override
- void didUpdateWidget(covariant VberSelect<T> oldWidget) {
- super.didUpdateWidget(oldWidget);
- // 当外部传入的value发生变化时,同步更新内部状态
- if (oldWidget.value != widget.value) {
- setState(() {
- _selectedValue = widget.value;
- });
- }
- }
- Future<void> _loadData() async {
- // 如果提供了fetchData方法,则优先使用它获取数据
- if (widget.fetchData != null) {
- // 使用Future.microtask确保在下一个微任务中加载数据,避免在构建过程中修改状态
- Future.microtask(() async {
- setState(() {
- _loading = true;
- });
- try {
- final data = await widget.fetchData!();
- setState(() {
- _items = data;
- _loading = false;
- });
- } catch (e) {
- setState(() {
- _loading = false;
- });
- }
- });
- } else {
- // 否则使用传入的静态数据
- setState(() {
- _items = widget.items;
- });
- }
- }
- @override
- Widget build(BuildContext context) {
- if (_loading) {
- Widget dropdownWidget = DropdownButton<String>(
- items: [],
- hint: SizedBox(
- width: 16,
- height: 16,
- child: CircularProgressIndicator(strokeWidth: 2),
- ),
- onChanged: (String? value) {},
- );
- Widget selectWidget = widget.hideUnderline
- ? DropdownButtonHideUnderline(child: dropdownWidget)
- : dropdownWidget;
- if (widget.showClearButton) {
- return Row(
- children: [
- Expanded(child: selectWidget),
- IconButton(
- icon: const Icon(Icons.clear, size: 20),
- onPressed: widget.enabled
- ? () {
- setState(() {
- _selectedValue = null;
- });
- widget.onChanged?.call(null);
- }
- : null,
- ),
- ],
- );
- }
- return selectWidget;
- }
- // 构建最终的下拉选项列表
- List<DropdownMenuItem<String>> dropdownItems = [];
- // 如果showAll为true,添加"全部"选项
- if (widget.showAll) {
- dropdownItems.add(DropdownMenuItem<String>(value: '', child: Text('全部')));
- }
- // 只有当_items不为null且不为空时才添加实际选项
- if (_items != null && _items!.isNotEmpty) {
- final options = _items!.map((item) => widget.converter(item)).toList();
- // 添加转换后的选项
- dropdownItems.addAll(
- options.map((option) {
- return DropdownMenuItem<String>(
- value: option.value,
- child: Text(option.label),
- );
- }).toList(),
- );
- }
- Widget dropdownWidget = DropdownButton<String>(
- value: _selectedValue,
- hint: Text(widget.hint ?? '请选择'),
- items: dropdownItems,
- onChanged: widget.enabled
- ? (String? newValue) {
- setState(() {
- _selectedValue = newValue;
- });
- widget.onChanged?.call(newValue);
- }
- : null,
- isExpanded: true,
- );
- Widget selectWidget = widget.hideUnderline
- ? DropdownButtonHideUnderline(child: dropdownWidget)
- : dropdownWidget;
- if (widget.showClearButton) {
- return Row(
- children: [
- Expanded(child: selectWidget),
- IconButton(
- icon: const Icon(Icons.clear, size: 20),
- onPressed: widget.enabled
- ? () {
- setState(() {
- _selectedValue = null;
- });
- widget.onChanged?.call(null);
- }
- : null,
- ),
- ],
- );
- }
- return selectWidget;
- }
- }
|