flutter_integrated_whb/lib/customWidget/bottom_picker.dart

99 lines
3.1 KiB
Dart
Raw Normal View History

2025-07-11 11:03:21 +08:00
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
2025-07-28 14:22:07 +08:00
import 'package:qhd_prevention/customWidget/toast_util.dart';
2025-07-11 11:03:21 +08:00
/// 通用底部弹窗选择器
/// Example:
/// ```dart
/// final choice = await BottomPicker.show<String>(
/// context,
/// items: ['选项1', '选项2', '选项3'],
/// itemBuilder: (item) => Text(item, textAlign: TextAlign.center),
/// initialIndex: 1,
/// );
/// if (choice != null) {
/// // 用户点击确定并选择了 choice
/// }
/// ```
class BottomPicker {
/// 显示底部选择器弹窗
///
/// [items]: 选项列表
/// [itemBuilder]: 每个选项的展示 Widget
/// [initialIndex]: 初始选中索引
/// [itemExtent]: 列表行高
/// [height]: 弹窗总高度
static Future<T?> show<T>(
2025-08-01 16:41:44 +08:00
BuildContext context, {
required List<T> items,
required Widget Function(T item) itemBuilder,
int initialIndex = 0,
double itemExtent = 40.0,
double height = 250,
}) {
2025-07-28 14:22:07 +08:00
if (items.isEmpty) return Future.value(null);
// 确保初始索引合法
final safeIndex = initialIndex.clamp(0, items.length - 1);
2025-07-11 11:03:21 +08:00
// 当前选中项
2025-07-28 14:22:07 +08:00
T selected = items[safeIndex];
2025-07-11 11:03:21 +08:00
return showModalBottomSheet<T>(
context: context,
backgroundColor: Colors.white,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(12)),
),
builder: (ctx) {
return SizedBox(
height: height,
child: Column(
children: [
// 按钮行
Padding(
2025-08-01 16:41:44 +08:00
padding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 8,
),
2025-07-11 11:03:21 +08:00
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
TextButton(
2025-08-01 16:41:44 +08:00
onPressed: () {
FocusScope.of(context).unfocus();
Navigator.of(ctx).pop();
},
2025-08-14 15:05:48 +08:00
child: const Text('取消', style: TextStyle(color: Colors.black54, fontSize: 16),),
2025-07-11 11:03:21 +08:00
),
TextButton(
2025-08-01 16:41:44 +08:00
onPressed: () {
FocusScope.of(context).unfocus();
Navigator.of(ctx).pop(selected);
},
2025-08-14 15:05:48 +08:00
child: const Text('确定', style: TextStyle(color: Colors.blue, fontSize: 16),),
2025-07-11 11:03:21 +08:00
),
],
),
),
const Divider(height: 1),
// 滚动选择器
Expanded(
child: CupertinoPicker(
2025-08-01 16:41:44 +08:00
scrollController: FixedExtentScrollController(
initialItem: initialIndex,
),
2025-07-11 11:03:21 +08:00
itemExtent: 30,
onSelectedItemChanged: (index) {
selected = items[index];
},
children: items.map(itemBuilder).toList(),
),
),
],
),
);
},
);
}
}