2025-07-25 18:06:37 +08:00
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
import 'package:flutter/cupertino.dart';
|
|
|
|
|
|
|
|
/// 通用底部弹窗选择器
|
|
|
|
/// Example:
|
|
|
|
/// ```dart
|
|
|
|
/// final choice = await BottomPickerTwo.show<String>(
|
|
|
|
/// context,
|
|
|
|
/// items: ['选项1', '选项2', '选项3'],
|
|
|
|
/// itemBuilder: (item) => Text(item, textAlign: TextAlign.center),
|
|
|
|
/// initialIndex: 1,
|
|
|
|
/// );
|
|
|
|
/// if (choice != null) {
|
|
|
|
/// // 用户点击确定并选择了 choice
|
|
|
|
/// }
|
|
|
|
/// ```
|
|
|
|
class BottomPickerTwo {
|
|
|
|
/// 显示底部选择器弹窗
|
|
|
|
///
|
|
|
|
/// [items]: 选项列表
|
|
|
|
/// [itemBuilder]: 每个选项的展示 Widget
|
|
|
|
/// [initialIndex]: 初始选中索引
|
|
|
|
/// [itemExtent]: 列表行高
|
|
|
|
/// [height]: 弹窗总高度
|
|
|
|
static Future<dynamic> show<T>(
|
2025-08-27 16:14:10 +08:00
|
|
|
BuildContext context, {
|
|
|
|
required List<dynamic> items,
|
|
|
|
required Widget Function(dynamic item) itemBuilder,
|
|
|
|
int initialIndex = 0,
|
|
|
|
double itemExtent = 40.0,
|
|
|
|
double height = 250,
|
|
|
|
double desiredSpacing = 16.0,
|
|
|
|
}) {
|
2025-07-25 18:06:37 +08:00
|
|
|
// 当前选中项
|
2025-07-29 08:53:00 +08:00
|
|
|
dynamic selected = items[initialIndex];
|
2025-07-25 18:06:37 +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-27 16:14:10 +08:00
|
|
|
padding: const EdgeInsets.symmetric(
|
|
|
|
horizontal: 16,
|
|
|
|
vertical: 8,
|
|
|
|
),
|
2025-07-25 18:06:37 +08:00
|
|
|
child: Row(
|
|
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
|
|
children: [
|
|
|
|
TextButton(
|
|
|
|
onPressed: () => Navigator.of(ctx).pop(),
|
|
|
|
child: const Text('取消'),
|
|
|
|
),
|
|
|
|
TextButton(
|
2025-07-29 08:53:00 +08:00
|
|
|
onPressed: () => Navigator.of(ctx).pop(selected["NAME"]),
|
2025-07-25 18:06:37 +08:00
|
|
|
child: const Text('确定'),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
const Divider(height: 1),
|
|
|
|
// 滚动选择器
|
|
|
|
Expanded(
|
|
|
|
child: CupertinoPicker(
|
2025-08-27 16:14:10 +08:00
|
|
|
scrollController: FixedExtentScrollController(
|
|
|
|
initialItem: initialIndex,
|
|
|
|
),
|
|
|
|
itemExtent: 35,
|
2025-07-25 18:06:37 +08:00
|
|
|
onSelectedItemChanged: (index) {
|
|
|
|
selected = items[index];
|
|
|
|
},
|
2025-08-27 16:14:10 +08:00
|
|
|
// children: items.map(itemBuilder).toList(),
|
|
|
|
children: List<Widget>.generate(items.length, (int index) {
|
|
|
|
return Padding(
|
|
|
|
// 通过Padding调整项间距
|
|
|
|
padding: EdgeInsets.symmetric(
|
|
|
|
vertical: desiredSpacing / 2,
|
|
|
|
),
|
|
|
|
child: Center(
|
|
|
|
child: Text(
|
|
|
|
// '选项 $index',
|
|
|
|
items[index]["NAME"],
|
|
|
|
style: TextStyle(
|
|
|
|
fontSize: 18,
|
|
|
|
color:
|
|
|
|
index == selected
|
|
|
|
? CupertinoColors.activeBlue
|
|
|
|
: CupertinoColors.inactiveGray,
|
|
|
|
fontWeight:
|
|
|
|
index == selected
|
|
|
|
? FontWeight.bold
|
|
|
|
: FontWeight.normal,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}),
|
2025-07-25 18:06:37 +08:00
|
|
|
),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
);
|
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|