2023-12-14 10:02:52 +08:00
|
|
|
|
import 'package:flutter/cupertino.dart';
|
|
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
|
|
import 'package:star_lock/tools/pickers/style/picker_style.dart';
|
|
|
|
|
|
// import 'package:flutter_pickers/style/picker_style.dart';
|
|
|
|
|
|
|
|
|
|
|
|
import '../locations_data.dart';
|
|
|
|
|
|
|
|
|
|
|
|
typedef AddressCallback(String province, String city, String? town);
|
|
|
|
|
|
|
|
|
|
|
|
/// 自定义 地区选择器
|
|
|
|
|
|
/// [initProvince] 初始化 省
|
|
|
|
|
|
/// [initCity] 初始化 市
|
|
|
|
|
|
/// [initTown] 初始化 区
|
|
|
|
|
|
/// [onChanged] 选择器发生变动
|
|
|
|
|
|
/// [onConfirm] 选择器提交
|
|
|
|
|
|
/// [addAllItem] 市、区是否添加 '全部' 选项 默认:true
|
|
|
|
|
|
class AddressPickerRoute<T> extends PopupRoute<T> {
|
|
|
|
|
|
AddressPickerRoute({
|
|
|
|
|
|
required this.addAllItem,
|
|
|
|
|
|
required this.pickerStyle,
|
|
|
|
|
|
required this.initProvince,
|
|
|
|
|
|
required this.initCity,
|
|
|
|
|
|
this.initTown,
|
|
|
|
|
|
this.onChanged,
|
|
|
|
|
|
this.onConfirm,
|
|
|
|
|
|
this.onCancel,
|
|
|
|
|
|
this.theme,
|
|
|
|
|
|
this.barrierLabel,
|
|
|
|
|
|
RouteSettings? settings,
|
|
|
|
|
|
}) : super(settings: settings);
|
|
|
|
|
|
|
|
|
|
|
|
late final String initProvince, initCity;
|
|
|
|
|
|
final String? initTown;
|
|
|
|
|
|
final AddressCallback? onChanged;
|
|
|
|
|
|
final AddressCallback? onConfirm;
|
|
|
|
|
|
final Function(bool isCancel)? onCancel;
|
|
|
|
|
|
final ThemeData? theme;
|
|
|
|
|
|
final bool addAllItem;
|
|
|
|
|
|
|
|
|
|
|
|
late final PickerStyle pickerStyle;
|
|
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
|
Duration get transitionDuration => const Duration(milliseconds: 200);
|
|
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
|
bool get barrierDismissible => true;
|
|
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
|
bool didPop(T? result) {
|
|
|
|
|
|
if (onCancel != null) {
|
|
|
|
|
|
if (result == null) {
|
|
|
|
|
|
onCancel!(false);
|
|
|
|
|
|
} else if (!(result as bool)) {
|
|
|
|
|
|
onCancel!(true);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return super.didPop(result);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
|
final String? barrierLabel;
|
|
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
|
Color get barrierColor => Colors.black54;
|
|
|
|
|
|
|
|
|
|
|
|
AnimationController? _animationController;
|
|
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
|
AnimationController createAnimationController() {
|
|
|
|
|
|
assert(_animationController == null);
|
|
|
|
|
|
_animationController =
|
|
|
|
|
|
BottomSheet.createAnimationController(navigator!.overlay!);
|
|
|
|
|
|
return _animationController!;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
|
Widget buildPage(BuildContext context, Animation<double> animation,
|
|
|
|
|
|
Animation<double> secondaryAnimation) {
|
|
|
|
|
|
Widget bottomSheet = MediaQuery.removePadding(
|
|
|
|
|
|
context: context,
|
|
|
|
|
|
removeTop: true,
|
|
|
|
|
|
child: _PickerContentView(
|
|
|
|
|
|
initProvince: initProvince,
|
|
|
|
|
|
initCity: initCity,
|
|
|
|
|
|
initTown: initTown,
|
|
|
|
|
|
addAllItem: addAllItem,
|
|
|
|
|
|
pickerStyle: pickerStyle,
|
|
|
|
|
|
route: this,
|
|
|
|
|
|
),
|
|
|
|
|
|
);
|
|
|
|
|
|
if (theme != null) {
|
|
|
|
|
|
bottomSheet = Theme(data: theme!, child: bottomSheet);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return bottomSheet;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class _PickerContentView extends StatefulWidget {
|
2024-11-20 10:04:55 +08:00
|
|
|
|
const _PickerContentView({
|
2023-12-14 10:02:52 +08:00
|
|
|
|
required this.initProvince,
|
|
|
|
|
|
required this.initCity,
|
|
|
|
|
|
required this.pickerStyle,
|
|
|
|
|
|
required this.addAllItem,
|
|
|
|
|
|
required this.route,
|
2024-11-20 10:04:55 +08:00
|
|
|
|
Key? key,
|
|
|
|
|
|
this.initTown,
|
2023-12-14 10:02:52 +08:00
|
|
|
|
}) : super(key: key);
|
|
|
|
|
|
|
|
|
|
|
|
final String initProvince, initCity;
|
|
|
|
|
|
final String? initTown;
|
|
|
|
|
|
final AddressPickerRoute route;
|
|
|
|
|
|
final bool addAllItem;
|
|
|
|
|
|
final PickerStyle pickerStyle;
|
|
|
|
|
|
|
|
|
|
|
|
@override
|
2024-11-20 10:04:55 +08:00
|
|
|
|
State<StatefulWidget> createState() =>
|
|
|
|
|
|
_PickerState(initProvince, initCity, initTown, addAllItem, pickerStyle);
|
2023-12-14 10:02:52 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class _PickerState extends State<_PickerContentView> {
|
|
|
|
|
|
final PickerStyle _pickerStyle;
|
|
|
|
|
|
late String _currentProvince, _currentCity;
|
|
|
|
|
|
String? _currentTown;
|
2024-11-20 10:04:55 +08:00
|
|
|
|
List cities = [];
|
|
|
|
|
|
List towns = [];
|
|
|
|
|
|
List provinces = [];
|
2023-12-14 10:02:52 +08:00
|
|
|
|
|
|
|
|
|
|
// 是否显示县级
|
|
|
|
|
|
bool hasTown = true;
|
|
|
|
|
|
|
|
|
|
|
|
// 是否添加全部
|
|
|
|
|
|
late final bool addAllItem;
|
|
|
|
|
|
|
|
|
|
|
|
AnimationController? controller;
|
|
|
|
|
|
Animation<double>? animation;
|
|
|
|
|
|
|
|
|
|
|
|
late FixedExtentScrollController provinceScrollCtrl,
|
|
|
|
|
|
cityScrollCtrl,
|
|
|
|
|
|
townScrollCtrl;
|
|
|
|
|
|
|
|
|
|
|
|
_PickerState(this._currentProvince, this._currentCity, this._currentTown,
|
|
|
|
|
|
this.addAllItem, this._pickerStyle) {
|
|
|
|
|
|
provinces = Address.provinces;
|
2024-11-20 10:04:55 +08:00
|
|
|
|
hasTown = _currentTown != null;
|
2023-12-14 10:02:52 +08:00
|
|
|
|
|
|
|
|
|
|
_init();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
|
void dispose() {
|
|
|
|
|
|
provinceScrollCtrl.dispose();
|
|
|
|
|
|
cityScrollCtrl.dispose();
|
|
|
|
|
|
townScrollCtrl.dispose();
|
|
|
|
|
|
|
|
|
|
|
|
super.dispose();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
|
|
return GestureDetector(
|
|
|
|
|
|
child: AnimatedBuilder(
|
|
|
|
|
|
animation: widget.route.animation!,
|
|
|
|
|
|
builder: (BuildContext context, Widget? child) {
|
|
|
|
|
|
return ClipRect(
|
|
|
|
|
|
child: CustomSingleChildLayout(
|
|
|
|
|
|
delegate: _BottomPickerLayout(
|
2024-11-20 10:04:55 +08:00
|
|
|
|
widget.route.animation!.value, _pickerStyle),
|
2023-12-14 10:02:52 +08:00
|
|
|
|
child: GestureDetector(
|
|
|
|
|
|
child: Material(
|
|
|
|
|
|
color: Colors.transparent,
|
|
|
|
|
|
child: _renderPickerView(),
|
|
|
|
|
|
),
|
|
|
|
|
|
),
|
|
|
|
|
|
),
|
|
|
|
|
|
);
|
|
|
|
|
|
},
|
|
|
|
|
|
),
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
_init() {
|
|
|
|
|
|
Address.addAllItem = addAllItem;
|
|
|
|
|
|
int pindex = 0;
|
|
|
|
|
|
int cindex = 0;
|
|
|
|
|
|
int tindex = 0;
|
|
|
|
|
|
pindex = provinces.indexWhere((p) => p == _currentProvince);
|
|
|
|
|
|
pindex = pindex >= 0 ? pindex : 0;
|
2024-11-20 10:04:55 +08:00
|
|
|
|
final String? selectedProvince = provinces[pindex];
|
2023-12-14 10:02:52 +08:00
|
|
|
|
if (selectedProvince != null) {
|
|
|
|
|
|
_currentProvince = selectedProvince;
|
|
|
|
|
|
|
|
|
|
|
|
cities = Address.getCities(selectedProvince);
|
|
|
|
|
|
|
|
|
|
|
|
cindex = cities.indexWhere((c) => c['name'] == _currentCity);
|
|
|
|
|
|
cindex = cindex >= 0 ? cindex : 0;
|
|
|
|
|
|
_currentCity = cities[cindex]['name'];
|
|
|
|
|
|
|
2024-04-26 15:38:59 +08:00
|
|
|
|
// AppLog.log('longer >>> 外面接到的$cities');
|
2023-12-14 10:02:52 +08:00
|
|
|
|
|
|
|
|
|
|
if (hasTown) {
|
|
|
|
|
|
towns = Address.getTowns(cities[cindex]['cityCode']);
|
|
|
|
|
|
tindex = towns.indexWhere((t) => t == _currentTown);
|
|
|
|
|
|
tindex = tindex >= 0 ? tindex : 0;
|
2024-11-20 10:04:55 +08:00
|
|
|
|
if (towns.isEmpty) {
|
2023-12-14 10:02:52 +08:00
|
|
|
|
_currentTown = '';
|
|
|
|
|
|
} else {
|
|
|
|
|
|
_currentTown = towns[tindex];
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-11-20 10:04:55 +08:00
|
|
|
|
provinceScrollCtrl = FixedExtentScrollController(initialItem: pindex);
|
|
|
|
|
|
cityScrollCtrl = FixedExtentScrollController(initialItem: cindex);
|
|
|
|
|
|
townScrollCtrl = FixedExtentScrollController(initialItem: tindex);
|
2023-12-14 10:02:52 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void _setProvince(int index) {
|
2024-11-20 10:04:55 +08:00
|
|
|
|
final String selectedProvince = provinces[index];
|
2024-04-26 15:38:59 +08:00
|
|
|
|
// AppLog.log('longer >>> index:$index _currentProvince:$_currentProvince selectedProvince:$selectedProvince ');
|
2023-12-14 10:02:52 +08:00
|
|
|
|
|
|
|
|
|
|
if (_currentProvince != selectedProvince) {
|
|
|
|
|
|
setState(() {
|
|
|
|
|
|
_currentProvince = selectedProvince;
|
|
|
|
|
|
|
|
|
|
|
|
cities = Address.getCities(selectedProvince);
|
2024-04-26 15:38:59 +08:00
|
|
|
|
// AppLog.log('longer >>> 返回的城市数据:$cities');
|
2023-12-14 10:02:52 +08:00
|
|
|
|
|
|
|
|
|
|
_currentCity = cities[0]['name'];
|
|
|
|
|
|
cityScrollCtrl.jumpToItem(0);
|
|
|
|
|
|
if (hasTown) {
|
|
|
|
|
|
towns = Address.getTowns(cities[0]['cityCode']);
|
|
|
|
|
|
_currentTown = towns[0];
|
|
|
|
|
|
townScrollCtrl.jumpToItem(0);
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
_notifyLocationChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void _setCity(int index) {
|
|
|
|
|
|
index = cities.length > index ? index : 0;
|
2024-11-20 10:04:55 +08:00
|
|
|
|
final String selectedCity = cities[index]['name'];
|
2023-12-14 10:02:52 +08:00
|
|
|
|
if (_currentCity != selectedCity) {
|
|
|
|
|
|
setState(() {
|
|
|
|
|
|
_currentCity = selectedCity;
|
|
|
|
|
|
if (hasTown) {
|
|
|
|
|
|
towns = Address.getTowns(cities[index]['cityCode']);
|
|
|
|
|
|
_currentTown = towns.isNotEmpty ? towns[0] : '';
|
|
|
|
|
|
townScrollCtrl.jumpToItem(0);
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
_notifyLocationChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void _setTown(int index) {
|
|
|
|
|
|
index = towns.length > index ? index : 0;
|
2024-11-20 10:04:55 +08:00
|
|
|
|
final String selectedTown = towns[index];
|
2023-12-14 10:02:52 +08:00
|
|
|
|
if (_currentTown != selectedTown) {
|
|
|
|
|
|
_currentTown = selectedTown;
|
|
|
|
|
|
_notifyLocationChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void _notifyLocationChanged() {
|
|
|
|
|
|
if (widget.route.onChanged != null) {
|
|
|
|
|
|
widget.route.onChanged!(_currentProvince, _currentCity, _currentTown);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
double _pickerFontSize(String text) {
|
2024-11-20 10:04:55 +08:00
|
|
|
|
final double ratio = hasTown ? 0.0 : 2.0;
|
2023-12-14 10:02:52 +08:00
|
|
|
|
if (text.length <= 6) {
|
|
|
|
|
|
return 18.0;
|
|
|
|
|
|
} else if (text.length < 9) {
|
|
|
|
|
|
return 16.0 + ratio;
|
|
|
|
|
|
} else if (text.length < 13) {
|
|
|
|
|
|
return 12.0 + ratio;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return 10.0 + ratio;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Widget _renderPickerView() {
|
2024-11-20 10:04:55 +08:00
|
|
|
|
final Widget itemView = _renderItemView();
|
2023-12-14 10:02:52 +08:00
|
|
|
|
|
|
|
|
|
|
if (!_pickerStyle.showTitleBar && _pickerStyle.menu == null) {
|
|
|
|
|
|
return itemView;
|
|
|
|
|
|
}
|
2024-11-20 10:04:55 +08:00
|
|
|
|
final List<Widget> viewList = <Widget>[];
|
2023-12-14 10:02:52 +08:00
|
|
|
|
if (_pickerStyle.showTitleBar) {
|
|
|
|
|
|
viewList.add(_titleView());
|
|
|
|
|
|
}
|
|
|
|
|
|
if (_pickerStyle.menu != null) {
|
|
|
|
|
|
viewList.add(_pickerStyle.menu!);
|
|
|
|
|
|
}
|
|
|
|
|
|
viewList.add(itemView);
|
|
|
|
|
|
|
|
|
|
|
|
return Column(children: viewList);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Widget _renderItemView() {
|
|
|
|
|
|
return Container(
|
|
|
|
|
|
height: _pickerStyle.pickerHeight,
|
|
|
|
|
|
color: _pickerStyle.backgroundColor,
|
|
|
|
|
|
child: Row(
|
|
|
|
|
|
children: <Widget>[
|
|
|
|
|
|
Expanded(
|
|
|
|
|
|
child: Container(
|
|
|
|
|
|
padding: const EdgeInsets.all(8.0),
|
|
|
|
|
|
child: CupertinoPicker.builder(
|
|
|
|
|
|
scrollController: provinceScrollCtrl,
|
|
|
|
|
|
selectionOverlay: _pickerStyle.itemOverlay,
|
|
|
|
|
|
itemExtent: _pickerStyle.pickerItemHeight,
|
2024-11-20 10:04:55 +08:00
|
|
|
|
onSelectedItemChanged: _setProvince,
|
2023-12-14 10:02:52 +08:00
|
|
|
|
childCount: Address.provinces.length,
|
2024-11-20 10:04:55 +08:00
|
|
|
|
itemBuilder: (_, int index) {
|
|
|
|
|
|
final String text = Address.provinces[index];
|
2023-12-14 10:02:52 +08:00
|
|
|
|
return Align(
|
|
|
|
|
|
alignment: Alignment.center,
|
|
|
|
|
|
child: Text(text,
|
|
|
|
|
|
style: TextStyle(
|
|
|
|
|
|
color: _pickerStyle.textColor,
|
|
|
|
|
|
fontSize:
|
|
|
|
|
|
_pickerStyle.textSize ?? _pickerFontSize(text),
|
|
|
|
|
|
),
|
|
|
|
|
|
textAlign: TextAlign.start));
|
|
|
|
|
|
},
|
|
|
|
|
|
),
|
|
|
|
|
|
),
|
|
|
|
|
|
),
|
|
|
|
|
|
Expanded(
|
|
|
|
|
|
child: Container(
|
2024-11-20 10:04:55 +08:00
|
|
|
|
padding: const EdgeInsets.all(8.0),
|
2023-12-14 10:02:52 +08:00
|
|
|
|
child: CupertinoPicker.builder(
|
|
|
|
|
|
scrollController: cityScrollCtrl,
|
|
|
|
|
|
selectionOverlay: _pickerStyle.itemOverlay,
|
|
|
|
|
|
itemExtent: _pickerStyle.pickerItemHeight,
|
2024-11-20 10:04:55 +08:00
|
|
|
|
onSelectedItemChanged: _setCity,
|
2023-12-14 10:02:52 +08:00
|
|
|
|
childCount: cities.length,
|
2024-11-20 10:04:55 +08:00
|
|
|
|
itemBuilder: (_, int index) {
|
|
|
|
|
|
final String text = cities[index]['name'];
|
2023-12-14 10:02:52 +08:00
|
|
|
|
return Align(
|
|
|
|
|
|
alignment: Alignment.center,
|
2024-11-20 10:04:55 +08:00
|
|
|
|
child: Text(text,
|
2023-12-14 10:02:52 +08:00
|
|
|
|
style: TextStyle(
|
|
|
|
|
|
color: _pickerStyle.textColor,
|
|
|
|
|
|
fontSize:
|
|
|
|
|
|
_pickerStyle.textSize ?? _pickerFontSize(text),
|
|
|
|
|
|
),
|
|
|
|
|
|
textAlign: TextAlign.start),
|
|
|
|
|
|
);
|
|
|
|
|
|
},
|
|
|
|
|
|
)),
|
|
|
|
|
|
),
|
2024-11-20 10:04:55 +08:00
|
|
|
|
if (hasTown)
|
|
|
|
|
|
Expanded(
|
|
|
|
|
|
child: Container(
|
|
|
|
|
|
padding: const EdgeInsets.all(8.0),
|
|
|
|
|
|
child: CupertinoPicker.builder(
|
|
|
|
|
|
scrollController: townScrollCtrl,
|
|
|
|
|
|
selectionOverlay: _pickerStyle.itemOverlay,
|
|
|
|
|
|
itemExtent: _pickerStyle.pickerItemHeight,
|
|
|
|
|
|
onSelectedItemChanged: _setTown,
|
|
|
|
|
|
childCount: towns.length,
|
|
|
|
|
|
itemBuilder: (_, int index) {
|
|
|
|
|
|
final String text = towns[index];
|
|
|
|
|
|
return Align(
|
|
|
|
|
|
alignment: Alignment.center,
|
|
|
|
|
|
child: Text(text,
|
|
|
|
|
|
style: TextStyle(
|
|
|
|
|
|
color: _pickerStyle.textColor,
|
|
|
|
|
|
fontSize: _pickerStyle.textSize ??
|
|
|
|
|
|
_pickerFontSize(text),
|
|
|
|
|
|
),
|
|
|
|
|
|
textAlign: TextAlign.start),
|
|
|
|
|
|
);
|
|
|
|
|
|
},
|
|
|
|
|
|
)),
|
|
|
|
|
|
)
|
|
|
|
|
|
else
|
|
|
|
|
|
const SizedBox()
|
2023-12-14 10:02:52 +08:00
|
|
|
|
],
|
|
|
|
|
|
),
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 选择器上面的view
|
|
|
|
|
|
Widget _titleView() {
|
|
|
|
|
|
return Container(
|
|
|
|
|
|
height: _pickerStyle.pickerTitleHeight,
|
|
|
|
|
|
decoration: _pickerStyle.headDecoration,
|
|
|
|
|
|
child: Row(
|
|
|
|
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.center,
|
|
|
|
|
|
children: <Widget>[
|
|
|
|
|
|
/// 取消按钮
|
|
|
|
|
|
InkWell(
|
|
|
|
|
|
onTap: () => Navigator.pop(context, false),
|
|
|
|
|
|
child: _pickerStyle.cancelButton),
|
|
|
|
|
|
|
|
|
|
|
|
/// 标题
|
|
|
|
|
|
Expanded(child: _pickerStyle.title),
|
|
|
|
|
|
|
|
|
|
|
|
/// 确认按钮
|
|
|
|
|
|
InkWell(
|
|
|
|
|
|
onTap: () {
|
|
|
|
|
|
if (widget.route.onConfirm != null) {
|
|
|
|
|
|
widget.route.onConfirm!(
|
|
|
|
|
|
_currentProvince, _currentCity, _currentTown);
|
|
|
|
|
|
}
|
|
|
|
|
|
Navigator.pop(context, true);
|
|
|
|
|
|
},
|
|
|
|
|
|
child: _pickerStyle.commitButton)
|
|
|
|
|
|
],
|
|
|
|
|
|
),
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class _BottomPickerLayout extends SingleChildLayoutDelegate {
|
|
|
|
|
|
_BottomPickerLayout(this.progress, this.pickerStyle);
|
|
|
|
|
|
|
|
|
|
|
|
final double progress;
|
|
|
|
|
|
final PickerStyle pickerStyle;
|
|
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
|
BoxConstraints getConstraintsForChild(BoxConstraints constraints) {
|
|
|
|
|
|
double maxHeight = pickerStyle.pickerHeight;
|
|
|
|
|
|
if (pickerStyle.showTitleBar) {
|
|
|
|
|
|
maxHeight += pickerStyle.pickerTitleHeight;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (pickerStyle.menu != null) {
|
|
|
|
|
|
maxHeight += pickerStyle.menuHeight;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return BoxConstraints(
|
|
|
|
|
|
minWidth: constraints.maxWidth,
|
|
|
|
|
|
maxWidth: constraints.maxWidth,
|
|
|
|
|
|
minHeight: 0.0,
|
|
|
|
|
|
maxHeight: maxHeight);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
|
Offset getPositionForChild(Size size, Size childSize) {
|
2024-11-20 10:04:55 +08:00
|
|
|
|
final double height = size.height - childSize.height * progress;
|
2023-12-14 10:02:52 +08:00
|
|
|
|
return Offset(0.0, height);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
|
bool shouldRelayout(_BottomPickerLayout oldDelegate) {
|
|
|
|
|
|
return progress != oldDelegate.progress;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|