import 'package:ef/ef.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:vbvs_app/common/color/appConstants.dart'; import 'package:vbvs_app/common/util/FitTool.dart'; import 'package:vbvs_app/common/util/MyUtils.dart'; import 'package:vbvs_app/component/tool/ClickableContainer.dart'; import 'package:vbvs_app/controller/theme_controller/ThemeController.dart'; import 'package:vbvs_app/pages/common/selectDialog.dart'; Future showDateSelectionDialog(BuildContext context, {required DateTime checkDate, Function? checkChange, String title = "生日"}) { ThemeController themeController = Get.find(); List years = [], months = [], days = []; var days_select = [].obs; int day_len = 31; int year = DateTime.now().year; for (var i = 0; i < 100; i++) { years.insert(0, year - i); } for (var i = 1; i < 13; i++) { months.add(i); } for (var i = 1; i < 32; i++) { days.add(i); } int yearIndex = years.lastIndexOf(checkDate.year); int monthIndex = months.lastIndexOf(checkDate.month); day_len = DateTime.fromMillisecondsSinceEpoch( DateTime(years[yearIndex], months[monthIndex] + 1) .millisecondsSinceEpoch - 1000) .day; days_select.value = days.sublist(0, day_len); int dayIndex = days.lastIndexOf(checkDate.day); return showDialog( context: context, barrierDismissible: true, // 点击对话框外部可关闭 builder: (BuildContext context) { return Stack( children: [ Positioned( bottom: 0, // 控制弹窗距离顶部的位置 left: 0, right: 0, child: Material( color: Colors.transparent, child: Dialog( backgroundColor: themeController.currentColor.sc17, insetPadding: EdgeInsets.zero, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(0), ), child: Container( width: double.infinity, decoration: BoxDecoration( borderRadius: BorderRadius.only( topLeft: Radius.circular( AppConstants().normal_container_radius), topRight: Radius.circular( AppConstants().normal_container_radius), bottomLeft: Radius.circular(0.rpx), bottomRight: Radius.circular(0.rpx), ), ), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.center, children: [ Container( color: themeController.currentColor.sc5, alignment: Alignment.centerLeft, height: 80.rpx, child: Padding( padding: EdgeInsets.only(left: 30.rpx, right: 30.rpx), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.center, children: [ InkWell( child: Text( "日期.取消".tr, style: TextStyle( fontFamily: 'Readex Pro', color: themeController.currentColor.sc3, letterSpacing: 0, fontSize: AppConstants().normal_text_fontSize), ), onTap: () { Get.back(); }, ), Text( "$title", style: TextStyle( fontFamily: 'Readex Pro', color: themeController.currentColor.sc3, letterSpacing: 0, fontSize: AppConstants().title_text_fontSize), ), // closeIconWhite, InkWell( child: Text( "日期.确定".tr, style: TextStyle( fontFamily: 'Readex Pro', color: themeController.currentColor.sc2, letterSpacing: 0, fontSize: AppConstants().normal_text_fontSize), ), onTap: () { checkChange?.call(DateTime(years[yearIndex], months[monthIndex], days[dayIndex])); Get.back(); }, ) ], ), ), ), Container( height: 240.rpx, margin: EdgeInsets.only(top: 60.rpx, bottom: 60.rpx), padding: EdgeInsets.symmetric(horizontal: 30.rpx), child: Row( mainAxisAlignment: MainAxisAlignment.center, // ✅ 整体居中 crossAxisAlignment: CrossAxisAlignment.center, children: [ Row( children: [ SizedBox( width: 120.rpx, child: getOnePicker(context, years, yearIndex, (d) { yearIndex = d; dayIndex = 0; day_len = DateTime.fromMillisecondsSinceEpoch( DateTime( years[yearIndex], months[monthIndex] + 1) .millisecondsSinceEpoch - 1000) .day; days_select.value = days.sublist(0, day_len); }, "年".tr), ), ], ), SizedBox(width: 100.rpx), // 月 Row( children: [ SizedBox( width: 80.rpx, child: getOnePicker( context, months, monthIndex, (d) { monthIndex = d; dayIndex = 0; day_len = DateTime.fromMillisecondsSinceEpoch( DateTime( years[yearIndex], months[monthIndex] + 1) .millisecondsSinceEpoch - 1000) .day; days_select.value = days.sublist(0, day_len); }, "月".tr), ), ], ), SizedBox(width: 100.rpx), Row( children: [ SizedBox( width: 80.rpx, child: Obx(() { return getOnePicker( context, days_select, dayIndex, (d) { dayIndex = d; }, "日".tr); }), ), ], ), ], ), ) ], ), ), ), ), ), ], ); }, ); } TextStyle _unitStyle(BuildContext context) { return TextStyle( fontFamily: 'Readex Pro', color: themeController.currentColor.sc3, fontSize: 30.rpx, letterSpacing: 0, ); } getOnePicker(BuildContext context, List arr, int checkIndex, Function onSelectedItemChanged, String unit, {bool looping = false}) { ThemeController themeController = Get.find(); return CupertinoPicker( key: UniqueKey(), useMagnifier: false, itemExtent: 80.rpx, magnification: 1, diameterRatio: 3, squeeze: 1, looping: looping, scrollController: FixedExtentScrollController(initialItem: checkIndex), selectionOverlay: Container(), // 不要默认选中遮罩 onSelectedItemChanged: (int value) { onSelectedItemChanged.call(value); }, children: List.generate(arr.length, (index) { return Container( alignment: Alignment.center, child: Text( "${arr[index]}$unit", // ✅ 每项都带单位 style: TextStyle( fontFamily: 'Readex Pro', color: themeController.currentColor.sc3, fontSize: 30.rpx, ), ), ); }), ); } Future showHeightPickerDialog( BuildContext context, { required int initialHeight, // 初始身高(单位:cm) required Function(int selectedHeight) onConfirm, String title = "选择身高", }) async { List heights = List.generate(101, (index) => 120 + index); // 120~220cm int selectedIndex = heights.indexOf(initialHeight); // int tempIndex = selectedIndex; final RxInt tempIndex = RxInt(selectedIndex); // ✅ 改为 RxInt ThemeController themeController = Get.find(); await showDialog( context: context, barrierDismissible: true, builder: (BuildContext context) { return Stack( children: [ Positioned( bottom: 0, left: 0, right: 0, child: Material( color: Colors.transparent, child: Dialog( backgroundColor: themeController.currentColor.sc17, insetPadding: EdgeInsets.zero, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(0), ), child: Container( padding: EdgeInsets.fromLTRB(0.rpx, 0.rpx, 0.rpx, 90.rpx), child: Column( mainAxisSize: MainAxisSize.min, children: [ Container( padding: EdgeInsets.fromLTRB(30.rpx, 0.rpx, 30.rpx, 0.rpx), color: themeController.currentColor.sc5, height: 80.rpx, child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ ClickableContainer( backgroundColor: Colors.transparent, highlightColor: Colors.transparent, padding: EdgeInsets.only(top: 0), onTap: () { Get.back(); }, child: Container( alignment: Alignment.center, width: 110.rpx, height: 60.rpx, child: Text( "取消".tr, style: TextStyle( fontSize: 30.rpx, color: Colors.white, ), ), )), Text(title, style: TextStyle( fontFamily: 'Readex Pro', color: themeController.currentColor.sc3, fontSize: 30.rpx, )), ClickableContainer( backgroundColor: Colors.transparent, highlightColor: Colors.transparent, padding: EdgeInsets.only(top: 0), onTap: () { onConfirm( heights[tempIndex.value]); // ✅ 使用 .value Get.back(); }, child: Container( alignment: Alignment.center, width: 110.rpx, height: 60.rpx, child: Text( "确定".tr, style: TextStyle( fontSize: 30.rpx, color: themeController.currentColor.sc2, ), ), )), ], ), ), SizedBox(height: 20.rpx), Stack( children: [ Positioned.fill( child: IgnorePointer( child: Center( child: Container( height: 90.rpx, margin: EdgeInsets.symmetric(horizontal: 95.rpx), decoration: BoxDecoration( color: themeController.currentColor.sc2, borderRadius: BorderRadius.circular(16.rpx), ), ), ), ), ), SizedBox( height: 240.rpx, child: getOnePickers( context, heights, tempIndex, // ✅ 传入 RxInt unit: "cm", ), ), ], ), ], ), ), ), ), ), ], ); }, ); } Future showWeightPickerDialog( BuildContext context, { required String initialWeight, // 初始体重(单位:kg) required Function(int selectedWeight) onConfirm, String title = "选择体重", }) async { List weights = List.generate(151, (index) => 30 + index); // 30~180kg int selectedIndex = weights.indexOf(int.tryParse(initialWeight) ?? 50); final RxInt tempIndex = RxInt(selectedIndex); // ✅ 改为 RxInt ThemeController themeController = Get.find(); await showDialog( context: context, barrierDismissible: true, builder: (BuildContext context) { return Stack( children: [ Positioned( bottom: 0, left: 0, right: 0, child: Material( color: Colors.transparent, child: Dialog( backgroundColor: themeController.currentColor.sc17, insetPadding: EdgeInsets.zero, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(0), ), child: Container( padding: EdgeInsets.fromLTRB(0.rpx, 0.rpx, 0.rpx, 90.rpx), child: Column( mainAxisSize: MainAxisSize.min, children: [ // 标题 + 按钮 Container( padding: EdgeInsets.fromLTRB(30.rpx, 0.rpx, 30.rpx, 0.rpx), color: themeController.currentColor.sc5, height: 80.rpx, child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ ClickableContainer( backgroundColor: Colors.transparent, highlightColor: Colors.transparent, padding: EdgeInsets.only(top: 0), onTap: () { Navigator.of(context).pop(); }, child: Container( alignment: Alignment.center, width: 110.rpx, height: 60.rpx, child: Text( "取消".tr, style: TextStyle( fontSize: 30.rpx, color: Colors.white, ), ), )), Text(title.tr, style: TextStyle( fontFamily: 'Readex Pro', color: themeController.currentColor.sc3, fontSize: 30.rpx, )), ClickableContainer( backgroundColor: Colors.transparent, highlightColor: Colors.transparent, padding: EdgeInsets.only(top: 0), onTap: () { onConfirm( weights[tempIndex.value]); // ✅ 回调返回选中值 Get.back(); }, child: Container( alignment: Alignment.center, width: 110.rpx, height: 60.rpx, child: Text( "确定".tr, style: TextStyle( fontSize: 30.rpx, color: themeController.currentColor.sc2, ), ), )), ], ), ), SizedBox(height: 20.rpx), Stack( children: [ Positioned.fill( child: IgnorePointer( child: Center( child: Container( height: 90.rpx, margin: EdgeInsets.symmetric(horizontal: 95.rpx), decoration: BoxDecoration( color: themeController.currentColor.sc2, borderRadius: BorderRadius.circular(16.rpx), ), ), ), ), ), SizedBox( height: 240.rpx, child: getOnePickers( context, weights, tempIndex, // ✅ 传入 RxInt unit: "kg", ), ), ], ), ], ), ), ), ), ), ], ); }, ); }