使用 Material 的 ShowDialog 组件自定义弹窗
void showComfirm(BuildContext context, String msg, {Function comfirm, Function cancel, String comfirmTitle = '确认', String cancelTitle = '取消'}) { showDialog( context: context, builder: (BuildContext context) { return CustomDialog( backgroundColor: Color(0xffffffff), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(ScreenUtil.getInstance().setSize(16))), minWidth: ScreenUtil.getInstance().setSize(480), maxWidth: ScreenUtil.getInstance().setSize(480), minHeight: ScreenUtil.getInstance().setSize(240), child: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.center, mainAxisSize: MainAxisSize.min, children: <Widget>[ Container( constraints: BoxConstraints( minHeight: ScreenUtil.getInstance().setSize(150), ), decoration: BoxDecoration( border: Border( bottom: BorderSide( color: kLingyiGray, width: ScreenUtil.getInstance().setSize(1), ))), width: ScreenUtil.getInstance().setSize(480), padding: EdgeInsets.fromLTRB( ScreenUtil.getInstance().setSize(34), ScreenUtil.getInstance().setSize(34), ScreenUtil.getInstance().setSize(34), ScreenUtil.getInstance().setSize(34)), child: Text( msg, style: TextStyle( fontSize: ScreenUtil.getInstance().setSp(32), color: kLingyiText500), ), ), Container( height: ScreenUtil.getInstance().setSize(88), child: Flex( direction: Axis.horizontal, mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.center, children: <Widget>[ Expanded( flex: 1, child: GestureDetector( onTap: () { Navigator.of(context).pop(); if (cancel != null) cancel(); }, child: Text( cancelTitle, style: TextStyle( fontSize: ScreenUtil.getInstance().setSp(28), color: Color(0xff999999)), textAlign: TextAlign.center, ), )), Container( width: ScreenUtil.getInstance().setSize(1), height: ScreenUtil.getInstance().setSize(88), color: kLingyiGray, ), Expanded( flex: 1, child: GestureDetector( onTap: () { Navigator.of(context).pop(); if (comfirm != null) comfirm(); }, child: Text( comfirmTitle, style: TextStyle( fontSize: ScreenUtil.getInstance().setSp(28), color: Color(0xff4499ff)), textAlign: TextAlign.center, ), )) ], ), ), ], ), ); });}void showAlert(BuildContext context, String msg, {Function callback, String comfirmTitle = '确认'}) { showDialog( context: context, builder: (BuildContext context) { return CustomDialog( backgroundColor: Color(0xffffffff), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(ScreenUtil.getInstance().setSize(16))), minWidth: ScreenUtil.getInstance().setSize(480), maxWidth: ScreenUtil.getInstance().setSize(480), minHeight: ScreenUtil.getInstance().setSize(240), child: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.center, mainAxisSize: MainAxisSize.min, children: <Widget>[ Container( constraints: BoxConstraints( minHeight: ScreenUtil.getInstance().setSize(150), ), width: ScreenUtil.getInstance().setSize(480), decoration: BoxDecoration( border: Border( bottom: BorderSide( color: kLingyiGray, width: ScreenUtil.getInstance().setSize(1), ))), padding: EdgeInsets.fromLTRB( ScreenUtil.getInstance().setSize(34), ScreenUtil.getInstance().setSize(34), ScreenUtil.getInstance().setSize(34), ScreenUtil.getInstance().setSize(34)), child: Text( msg, style: TextStyle( fontSize: ScreenUtil.getInstance().setSp(32), color: kLingyiText500), textAlign: TextAlign.center, ), ), GestureDetector( onTap: () { Navigator.of(context).pop(); if (callback != null) callback(); }, child: Container( height: ScreenUtil.getInstance().setSize(88), alignment: Alignment.center, child: Text( comfirmTitle, style: TextStyle( fontSize: ScreenUtil.getInstance().setSp(28), color: Color(0xff4499ff)), ), ), ) ], ), ); });}void showToast(BuildContext context, String msg, {Function callback, int duration = 1500, bool isSuccess = true}) { Timer(Duration(milliseconds: duration), () { Navigator.pop(context); if (callback != null) callback(); }); customShowDialog( context: context, barrierDismissible: false, barrierColor: Color(0x00ffffff), builder: (BuildContext context) { return CustomDialog( backgroundColor: Color(0x88000000), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular( ScreenUtil.getInstance().setSize(12))), elevation: 0, child: Padding( padding: EdgeInsets.fromLTRB(20, 15, 20, 15), child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, mainAxisSize: MainAxisSize.min, children: <Widget>[ Icon( isSuccess ? Icons.done : Icons.error, size: ScreenUtil.getInstance().setSize(80), color: kLingyiWhite, ), SizedBox( height: ScreenUtil.getInstance().setSize(20), ), Text( msg, style: TextStyle( color: kLingyiWhite, fontSize: ScreenUtil.getInstance().setSp(28)), textAlign: TextAlign.center, maxLines: 3, overflow: TextOverflow.ellipsis, ) ], ), )); });}void showMsg(BuildContext context, String msg, {int duration = 1500, Function callback}) { Timer(Duration(milliseconds: duration), () { Navigator.of(context).pop(); if (callback != null) callback(); }); customShowDialog( context: context, barrierDismissible: false, barrierColor: Color(0x00ffffff), builder: (BuildContext context) { return CustomDialog( backgroundColor: Color(0x88000000), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(ScreenUtil.getInstance().setSize(8))), elevation: 0, minWidth: ScreenUtil.getInstance().setSize(300), maxWidth: ScreenUtil.getInstance().setSize(650), minHeight: ScreenUtil.getInstance().setSize(64), child: Stack( alignment: Alignment.center, children: <Widget>[ Padding( padding: EdgeInsets.fromLTRB(10, 0, 10, 0), child: Text( msg, style: TextStyle( color: kLingyiWhite, fontSize: ScreenUtil.getInstance().setSp(28)), textAlign: TextAlign.center, maxLines: 2, overflow: TextOverflow.ellipsis, ), ) ], )); });}class CustomDialog extends StatelessWidget { const CustomDialog({ Key key, this.backgroundColor, this.elevation, this.insetAnimationDuration = const Duration(milliseconds: 100), this.insetAnimationCurve = Curves.decelerate, this.shape, this.child, this.minWidth, this.maxWidth, this.minHeight, this.maxHeight, }) : super(key: key); final Color backgroundColor; final double elevation; final Duration insetAnimationDuration; final Curve insetAnimationCurve; final ShapeBorder shape; final Widget child; final double minWidth; final double maxWidth; final double minHeight; final double maxHeight; static const RoundedRectangleBorder _defaultDialogShape = RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(2.0))); static const double _defaultElevation = 24.0; @override Widget build(BuildContext context) { final DialogTheme dialogTheme = DialogTheme.of(context); return AnimatedPadding( padding: MediaQuery.of(context).viewInsets + const EdgeInsets.symmetric(horizontal: 0, vertical: 0), duration: insetAnimationDuration, curve: insetAnimationCurve, child: MediaQuery.removeViewInsets( removeLeft: true, removeTop: true, removeRight: true, removeBottom: true, context: context, child: Center( child: ConstrainedBox( constraints: BoxConstraints( minWidth: minWidth ?? ScreenUtil.getInstance().setSize(200), minHeight: minHeight ?? ScreenUtil.getInstance().setSize(200), maxWidth: maxWidth ?? ScreenUtil.getInstance().setSize(600), maxHeight: maxWidth ?? ScreenUtil.getInstance().setSize(600), ), child: Material( color: backgroundColor ?? dialogTheme.backgroundColor ?? Theme.of(context).dialogBackgroundColor, elevation: elevation ?? dialogTheme.elevation ?? _defaultElevation, shape: shape ?? dialogTheme.shape ?? _defaultDialogShape, type: MaterialType.card, child: child, ), ), ), ), ); }}Future<T> customShowDialog<T>({ @required BuildContext context, bool barrierDismissible = true, Color barrierColor = Colors.black54, @Deprecated( 'Instead of using the "child" argument, return the child from a closure ' 'provided to the "builder" argument. This will ensure that the BuildContext ' 'is appropriate for widgets built in the dialog.') Widget child, WidgetBuilder builder,}) { assert(child == null || builder == null); assert(debugCheckHasMaterialLocalizations(context)); final ThemeData theme = Theme.of(context, shadowThemeOnly: true); return showGeneralDialog( context: context, pageBuilder: (BuildContext buildContext, Animation<double> animation, Animation<double> secondaryAnimation) { final Widget pageChild = child ?? Builder(builder: builder); return SafeArea( child: Builder(builder: (BuildContext context) { return theme != null ? Theme(data: theme, child: pageChild) : pageChild; }), ); }, barrierDismissible: barrierDismissible, barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel, barrierColor: barrierColor, transitionDuration: const Duration(milliseconds: 150), transitionBuilder: _buildMaterialDialogTransitions, );}Widget _buildMaterialDialogTransitions( BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget child) { return FadeTransition( opacity: CurvedAnimation( parent: animation, curve: Curves.easeOut, ), child: child, );}
使用 Material 的 OverlayEntry组件自定义弹窗
import 'package:flutter/material.dart';import 'package:flutter/widgets.dart';import 'package:lingyi/config/color.dart';class ShowMsg { static void show(BuildContext context, String msg ,{ int duration = 1500, int gravity = 1, Color backgroundColor = const Color(0x88000000), Color textColor = Colors.white, double backgroundRadius, Border border, Function callback }) { MsgView.dismiss(); ToastView.dismiss(); MsgView.createView( msg, context, duration, gravity, backgroundColor, textColor, backgroundRadius, border, callback); }}class MsgView { static final MsgView _singleton = new MsgView._internal(); factory MsgView() { return _singleton; } MsgView._internal(); static OverlayState overlayState; static OverlayEntry _overlayEntry; static bool _isVisible = false; static void createView(String msg, BuildContext context, int duration, int gravity, Color background, Color textColor, double backgroundRadius, Border border, Function callback) async { overlayState = Overlay.of(context); _overlayEntry = new OverlayEntry( builder: (BuildContext context) => PositionWidget( widget: Container( width: MediaQuery.of(context).size.width, child: Container( alignment: Alignment.center, width: MediaQuery.of(context).size.width, child: Container( decoration: BoxDecoration( color: background, borderRadius: BorderRadius.circular(backgroundRadius ?? ScreenUtil.getInstance().setSize(8)), border: border, ), constraints: BoxConstraints( minWidth: ScreenUtil.getInstance().setSize(300), maxWidth: ScreenUtil.getInstance().setSize(650), minHeight: ScreenUtil.getInstance().setSize(64), ), margin: EdgeInsets.symmetric(horizontal: 20), padding: EdgeInsets.fromLTRB(10, 0, 10, 0), child: Stack( alignment: Alignment.center, children: <Widget>[ Text(msg, softWrap: true, style: TextStyle(fontSize: ScreenUtil.getInstance().setSize(28), color: textColor)), ] ) )), ), gravity: gravity), ); _isVisible = true; overlayState.insert(_overlayEntry); await new Future.delayed(Duration(milliseconds: duration ?? 2000)); if(callback != null) callback(); dismiss(); } static dismiss() async { if (!_isVisible) { return; } _isVisible = false; _overlayEntry?.remove(); }}class PositionWidget extends StatelessWidget { PositionWidget({ Key key, @required this.widget, @required this.gravity, }) : super(key: key); final Widget widget; final int gravity; @override Widget build(BuildContext context) { return new Positioned( top: gravity == 2 ? 50 : null, bottom: gravity == 0 ? 50 : null, child: Material( color: Colors.transparent, child: widget, )); }}// show Tost----------------------------------------------class ShowToast { static void show(BuildContext context, String msg ,{ bool isSuccess = true, int duration = 1500, Color backgroundColor, Color textColor = Colors.white, double backgroundRadius, Function callback }) { MsgView.dismiss(); ToastView.dismiss(); ToastView.createView( msg, context, isSuccess, duration, backgroundColor, textColor, backgroundRadius, callback); }}class ToastView { static final ToastView _singleton = new ToastView._internal(); factory ToastView() { return _singleton; } ToastView._internal(); static OverlayState overlayState; static OverlayEntry _overlayEntry; static bool _isVisible = false; static void createView(String msg, BuildContext context, bool isSuccess, int duration, Color background, Color textColor, double backgroundRadius, Function callback) async { overlayState = Overlay.of(context); _overlayEntry = new OverlayEntry( builder: (BuildContext context) => PositionWidget( widget: Stack( alignment: Alignment.center, children: <Widget>[ Container( decoration: BoxDecoration( color: background ?? Color(0x88000000), borderRadius: BorderRadius.circular(backgroundRadius ?? ScreenUtil.getInstance().setSize(12)) ), padding: EdgeInsets.fromLTRB(20, 10, 20, 10), child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, mainAxisSize: MainAxisSize.min, children: <Widget>[ Icon( isSuccess ? Icons.done : Icons.error, size: ScreenUtil.getInstance().setSize(80), color: textColor, ), SizedBox( height: ScreenUtil.getInstance().setSize(10), ), Text( msg, style: TextStyle( color: textColor, fontSize: ScreenUtil.getInstance().setSp(28)), textAlign: TextAlign.center, maxLines: 3, overflow: TextOverflow.ellipsis, ) ], ), ) ], ), gravity: 1), ); _isVisible = true; overlayState.insert(_overlayEntry); await new Future.delayed(Duration(milliseconds: duration ?? 2000)); if(callback != null) callback(); dismiss(); } static dismiss() async { if (!_isVisible) { return; } _isVisible = false; _overlayEntry?.remove(); }}// show Alert---------------------------------------------class ShowAlert { static void show(BuildContext context, String msg ,{ Color backgroundColor, double backgroundRadius, bool showCancel: true, String comfirmTitle: '确认', String cancelTitle: '取消', Function onConfirm, Function onCancel }) { MsgView.dismiss(); ToastView.dismiss(); AlertView.dismiss(); AlertView.createView(msg, context, backgroundColor, backgroundRadius, showCancel, comfirmTitle, cancelTitle, onConfirm, onCancel); }}class AlertView { static final AlertView _singleton = new AlertView._internal(); factory AlertView() { return _singleton; } AlertView._internal(); static OverlayState overlayState; static OverlayEntry _overlayEntry; static bool _isVisible = false; static void createView(String msg, BuildContext context, Color backgroundColor, double backgroundRadius, bool showCancel, String comfirmTitle, String cancelTitle, Function onConfirm, Function onCancel) async { overlayState = Overlay.of(context); _overlayEntry = new OverlayEntry( builder: (BuildContext context) => PositionWidget( widget: Container( color: Color(0x66000000), child: Stack( alignment: Alignment.center, children: <Widget>[ Container( decoration: BoxDecoration( color: backgroundColor ?? Colors.white, borderRadius: BorderRadius.circular(backgroundRadius ?? ScreenUtil.getInstance().setSize(16)) ), constraints: BoxConstraints( minWidth: ScreenUtil.getInstance().setSize(480), maxWidth: ScreenUtil.getInstance().setSize(480), minHeight: ScreenUtil.getInstance().setSize(240), ), padding: EdgeInsets.fromLTRB(0, 10, 0, 10), child: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.center, mainAxisSize: MainAxisSize.min, children: <Widget>[ Container( constraints: BoxConstraints( minHeight: ScreenUtil.getInstance().setSize(150), ), decoration: BoxDecoration( border: Border( bottom: BorderSide( color: kLingyiGray, width: ScreenUtil.getInstance().setSize(1), ))), width: ScreenUtil.getInstance().setSize(480), padding: EdgeInsets.fromLTRB( ScreenUtil.getInstance().setSize(34), ScreenUtil.getInstance().setSize(34), ScreenUtil.getInstance().setSize(34), ScreenUtil.getInstance().setSize(34)), child: Text( msg, style: TextStyle( fontSize: ScreenUtil.getInstance().setSp(32), color: kLingyiText500), ), ), Container( height: ScreenUtil.getInstance().setSize(88), child: !showCancel ? GestureDetector( onTap: () { dismiss(); if (onConfirm != null) onConfirm(); }, child: Center( child: Text( comfirmTitle, style: TextStyle( fontSize: ScreenUtil.getInstance().setSp(28), color: Color(0xff4499ff)), textAlign: TextAlign.center, ) ), ) : Flex( direction: Axis.horizontal, mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.center, children: <Widget>[ Expanded( flex: 1, child: GestureDetector( onTap: () { dismiss(); if (onCancel != null) onCancel(); }, child: Text( cancelTitle, style: TextStyle( fontSize: ScreenUtil.getInstance().setSp(28), color: Color(0xff999999)), textAlign: TextAlign.center, ), ) ), Container( width: ScreenUtil.getInstance().setSize(1), height: ScreenUtil.getInstance().setSize(88), color: kLingyiGray, ), Expanded( flex: 1, child: GestureDetector( onTap: () { dismiss(); if (onConfirm != null) onConfirm(); }, child: Text( comfirmTitle, style: TextStyle( fontSize: ScreenUtil.getInstance().setSp(28), color: Color(0xff4499ff)), textAlign: TextAlign.center, ), ) ) ], ), ), ], ), ) ], ), ), gravity: 1), ); _isVisible = true; overlayState.insert(_overlayEntry); } static dismiss() async { if (!_isVisible) { return; } _isVisible = false; _overlayEntry?.remove(); }}
使用 Material 的 showModalBottomSheet 和 Cupertino 的 CupertinoPicker 制作底部抽屉选择器
import 'package:flutter/cupertino.dart';import 'package:flutter/material.dart';import 'package:annotation_route/route.dart';import 'package:lingyi/config/color.dart';import 'package:lingyi/route/route.dart';import 'package:lingyi/util/common.dart';@ARoute(url: 'page://health/medicine')class Medicine extends StatefulWidget { final dynamic option; Medicine(this.option); @override MedicineState createState() => MedicineState();}class MedicineState extends State<Medicine> { bool isWork = true; // 是否提醒 List<Map> startList = []; List<Map> endList = []; List<Map> weekList = [{'isPick': false, 'showValue': '周一'},{'isPick': false, 'showValue': '周二'},{'isPick': false, 'showValue': '周三'},{'isPick': false, 'showValue': '周四'},{'isPick': false, 'showValue': '周五'},{'isPick': false, 'showValue': '周六'},{'isPick': false, 'showValue': '周日'},{'isPick': false, 'showValue': '每天'}]; List<String> durationList = ['7天','30天','90天','180天','365天',' 无期限','自定义']; String startDate = ''; String endDate = '选择周期'; String currentWeek = '请选择'; String ringing = '默认铃声'; int pickDateIndex = 0; // 选择开始时间下标 int pickWeekIndex = 7; // 选择重复下标 int pickDurationIndex = -1; // 选择周期时间下标 int pickEndIndex = 0; // 选择自定义周期下标 int pickHourIndex = 0; // 选择自定义周期下标 int pickMinuteIndex = 0; // 选择自定义周期下标 // List<Map> clockList = [{'showValue': '08:00', 'value': 480}, {'showValue': '09:30', 'value': 570}]; // 提醒闹钟列表 List<Map> clockList = []; // 提醒闹钟列表 List<String> hourList = []; List<String> minuteList = []; FixedExtentScrollController startScrollCtr = new FixedExtentScrollController(); FixedExtentScrollController endScrollCtr = new FixedExtentScrollController(); FixedExtentScrollController hourScrollCtr = new FixedExtentScrollController(); FixedExtentScrollController minuteScrollCtr = new FixedExtentScrollController(); // 今天的时间 var today = new DateTime.now(); String formatDate(DateTime date) { return date.year.toString() + '年' + date.month.toString() + '月' + date.day.toString() + '日 星期' + getWeekday(date.weekday); } String getWeekday(int num) { switch(num) { case 1: return '一'; break; case 2: return '二'; break; case 3: return '三'; break; case 4: return '四'; break; case 5: return '五'; break; case 6: return '六'; break; default: return '日'; break; } } void createStartDateList() { for(int i = 0; i < 90; i++ ) { var tempDay = today.add(new Duration(days: i)); Map tempObj = {'value': tempDay, 'showValue': formatDate(tempDay)}; startList.add(tempObj); } createEndDateList(today); setState(() { startDate = formatDate(today); }); } void createEndDateList(DateTime start) { endList = []; for(int i = 0; i < 366; i++) { var tempDay = start.add(new Duration(days: i)); Map tempObj = {'value': tempDay, 'showValue': formatDate(tempDay)}; endList.add(tempObj); } } void createHourList() { for(int i = 0; i < 24; i++) { hourList.add(i.toString().padLeft(2, '0')); } } void createMinuteList() { for(int i = 0; i < 60; i++) { minuteList.add(i.toString().padLeft(2, '0')); } } @override void initState() { super.initState(); createStartDateList(); createHourList(); createMinuteList(); } Iterable<Widget> get startDateItems sync* { for(int i = 0, length = startList.length; i < length; i++) { yield Container( height: ScreenUtil.getInstance().setSize(80), alignment: Alignment.center, child: Text(startList[i]['showValue'], style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(36), color: kLingyiText500)), ); } } Iterable<Widget> get endDateItems sync* { for(int i = 0, length = endList.length; i < length; i++) { yield Container( height: ScreenUtil.getInstance().setSize(80), alignment: Alignment.center, child: Text(endList[i]['showValue'], style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(36), color: kLingyiText500)), ); } } Iterable<Widget> get hourItems sync* { for(int i = 0, length = hourList.length; i < length; i++) { yield Container( height: ScreenUtil.getInstance().setSize(80), alignment: Alignment.center, child: Text(hourList[i], style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(36), color: kLingyiText500)), ); } } Iterable<Widget> get minuteItems sync* { for(int i = 0, length = minuteList.length; i < length; i++) { yield Container( height: ScreenUtil.getInstance().setSize(80), alignment: Alignment.center, child: Text(minuteList[i], style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(36), color: kLingyiText500)), ); } } void setCurrentWeek() { // 判断是否是全选 if(weekList.last['isPick']) { setState(() { currentWeek = '每天'; }); }else { var tempList = []; weekList.forEach((value) { if(value['isPick']) { tempList.add(value['showValue']); } }); setState(() { currentWeek = tempList.isEmpty ? '请选择' : tempList.join(','); }); } } void setEndDate() { var tempString = ''; switch(pickDurationIndex) { case 0: tempString = formatDate(startList[pickDateIndex]['value'].add(new Duration(days: 7))); break; case 1: tempString = formatDate(startList[pickDateIndex]['value'].add(new Duration(days: 30))); break; case 2: tempString = formatDate(startList[pickDateIndex]['value'].add(new Duration(days: 90))); break; case 3: tempString = formatDate(startList[pickDateIndex]['value'].add(new Duration(days: 180))); break; case 4: tempString = formatDate(startList[pickDateIndex]['value'].add(new Duration(days: 365))); break; case 5: tempString = '无期限'; break; default: tempString = endList[pickEndIndex]['showValue']; break; } setState(() { endDate = tempString; }); } void showClockPick(int value, {int editIndex=-1}) { // 初始化 pickHourIndex = 0; pickMinuteIndex = 0; int positionHour = value ~/ 60; int positionMinute = value.remainder(60); showModalBottomSheet( context: context, shape: RoundedRectangleBorder( borderRadius: BorderRadius.only( topLeft: Radius.circular(ScreenUtil.getInstance().setSize(16)), topRight: Radius.circular(ScreenUtil.getInstance().setSize(16)), ) ), builder: (context) { hourScrollCtr.jumpToItem(positionHour); minuteScrollCtr.jumpToItem(positionMinute); return Column( mainAxisSize: MainAxisSize.min, children: <Widget>[ Container( height: ScreenUtil.getInstance().setSize(105), alignment: Alignment.center, decoration: BoxDecoration( color: kLingyiWhite, border: Border(bottom: BorderSide(color: kLingyiGray, width: ScreenUtil.getInstance().setSize(1))) ), child: Text('设置提醒', style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(32), color: kLingyiOrange),), ), Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: <Widget>[ Expanded( flex: 1, child: Container( height: ScreenUtil.getInstance().setSize(480), child: CupertinoPicker( itemExtent: ScreenUtil.getInstance().setSize(80), onSelectedItemChanged: (index) { pickHourIndex = index; }, scrollController: hourScrollCtr, diameterRatio: 720.0, // 滚筒的曲率,就是弯曲的程度 useMagnifier: true, magnification: 1.0, looping: true, backgroundColor: kLingyiWhite, offAxisFraction: 100.0, // 子项的偏移 children: hourItems.toList(), ) ), ), Expanded( flex: 1, child: Container( height: ScreenUtil.getInstance().setSize(480), child: CupertinoPicker( itemExtent: ScreenUtil.getInstance().setSize(80), onSelectedItemChanged: (index) { pickMinuteIndex = index; }, scrollController: minuteScrollCtr, diameterRatio: 720.0, // 滚筒的曲率,就是弯曲的程度 useMagnifier: true, magnification: 1.0, looping: true, backgroundColor: kLingyiWhite, offAxisFraction: 100.0, // 子项的偏移 children: minuteItems.toList(), ) ), ) ], ), Container( height: ScreenUtil.getInstance().setSize(20), color: kLingyiGray100, ), Container( color: kLingyiWhite, padding: EdgeInsets.fromLTRB(ScreenUtil.getInstance().setSize(36), 0, ScreenUtil.getInstance().setSize(36), 0), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: <Widget>[ Expanded( flex: 1, child: GestureDetector( onTap: () { Navigator.pop(context); }, child: Container( height: ScreenUtil.getInstance().setSize(90), decoration: BoxDecoration( border: Border(right: BorderSide(color: kLingyiGray, width: ScreenUtil.getInstance().setSize(1))) ), alignment: Alignment.center, child: Text('取消', style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(32), color: kLingyiText100),), ), ) ), Expanded( flex: 1, child: GestureDetector( onTap: () { int tempValue = pickHourIndex * 60 + pickMinuteIndex; for(int i = 0, length = clockList.length; i < length; i++) { if(clockList[i]['value'] == tempValue) { showMsg(context, '已设置相同时刻的提醒'); return; } } // 判断是否是编辑 if(editIndex > -1) { clockList.removeAt(editIndex); } Map tempClock = { 'showValue': hourList[pickHourIndex] + ':' + minuteList[pickMinuteIndex], 'value': tempValue }; clockList.add(tempClock); // 按小到大排序 sortClock(); Navigator.pop(context); }, child: Container( height: ScreenUtil.getInstance().setSize(100), alignment: Alignment.center, child: Text('确认', style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(32), color: kLingyiGreen),), ), ) ), ], ), ), Container( color: kLingyiWhite, height: ScreenUtil.bottomBarHeight, ) ], ); }, ); } void sortClock() { if (clockList == null || clockList.isEmpty) return; clockList.sort((b, a) => b['value'].compareTo(a['value'])); setState(() {}); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.option.query['name']!=null?widget.option.query['name']:'吃药'), leading: goBackArr(context), actions: <Widget>[ Container( padding: EdgeInsets.only(right: 20), alignment: Alignment.center, child: MaterialButton( onPressed: () async { showToast(context, '保存成功', isSuccess: true, callback: () { Navigator.pop(context); }); }, color: kLingyiGreen, elevation: 0, minWidth: 50, height: 24, child: Text('保存', style: TextStyle( fontSize: ScreenUtil.getInstance().setSize(24), color: kLingyiWhite)), ), ), ], ), body: Container( width: MediaQuery.of(context).size.width, height: MediaQuery.of(context).size.height, color: kLingyiGray100, child: ListView( children: <Widget>[ Container( padding: EdgeInsets.only(left: ScreenUtil.getInstance().setSize(36)), color: kLingyiWhite, child: Container( height: ScreenUtil.getInstance().setSize(150), padding: EdgeInsets.only(right: ScreenUtil.getInstance().setSize(36)), decoration: BoxDecoration( border: Border(bottom: BorderSide(color: kLingyiGray, width: ScreenUtil.getInstance().setSize(1))) ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: <Widget>[ CircleAvatar( backgroundColor: kLingyiGray400, radius: ScreenUtil.getInstance().setSize(45), backgroundImage: getAssetImage(widget.option.query['icon']!=null?widget.option.query['icon']:'2_health/t_drug.png'), ), SizedBox( width: ScreenUtil.getInstance().setSize(520), child: Text(widget.option.query['name']!=null?widget.option.query['name']:'吃药', style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(32), color: kLingyiText500),), ), SizedBox( width: ScreenUtil.getInstance().setSize(30), ) // nextPageArr() ], ), ) ), // 开始时间 GestureDetector( onTap: () { showModalBottomSheet( context: context, shape: RoundedRectangleBorder( borderRadius: BorderRadius.only( topLeft: Radius.circular(ScreenUtil.getInstance().setSize(16)), topRight: Radius.circular(ScreenUtil.getInstance().setSize(16)), ) ), builder: (context) { startScrollCtr.jumpToItem(pickDateIndex); return Column( mainAxisSize: MainAxisSize.min, children: <Widget>[ Container( height: ScreenUtil.getInstance().setSize(105), alignment: Alignment.center, decoration: BoxDecoration( color: kLingyiWhite, border: Border(bottom: BorderSide(color: kLingyiGray, width: ScreenUtil.getInstance().setSize(1))) ), child: Text('开始时间', style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(32), color: kLingyiOrange),), ), Container( height: ScreenUtil.getInstance().setSize(480), child: CupertinoPicker( itemExtent: ScreenUtil.getInstance().setSize(80), onSelectedItemChanged: (index) { pickDateIndex = index; }, scrollController: startScrollCtr, diameterRatio: 720.0, // 滚筒的曲率,就是弯曲的程度 useMagnifier: true, magnification: 1.0, looping: true, backgroundColor: kLingyiWhite, offAxisFraction: 100.0, // 子项的偏移 children: startDateItems.toList(), ) ), Container( height: ScreenUtil.getInstance().setSize(20), color: kLingyiGray100, ), Container( color: kLingyiWhite, padding: EdgeInsets.fromLTRB(ScreenUtil.getInstance().setSize(36), 0, ScreenUtil.getInstance().setSize(36), 0), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: <Widget>[ Expanded( flex: 1, child: GestureDetector( onTap: () { Navigator.pop(context); }, child: Container( height: ScreenUtil.getInstance().setSize(90), decoration: BoxDecoration( border: Border(right: BorderSide(color: kLingyiGray, width: ScreenUtil.getInstance().setSize(1))) ), alignment: Alignment.center, child: Text('取消', style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(32), color: kLingyiText100),), ), ) ), Expanded( flex: 1, child: GestureDetector( onTap: () { setState(() { startDate = startList[pickDateIndex]['showValue']; }); createEndDateList(startList[pickDateIndex]['value']); Navigator.pop(context); }, child: Container( height: ScreenUtil.getInstance().setSize(100), alignment: Alignment.center, child: Text('确认', style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(32), color: kLingyiGreen),), ), ) ), ], ), ), Container( color: kLingyiWhite, height: ScreenUtil.bottomBarHeight, ) ], ); }, ); }, child: Container( padding: EdgeInsets.only(left: ScreenUtil.getInstance().setSize(36)), color: kLingyiWhite, child: Container( height: ScreenUtil.getInstance().setSize(100), padding: EdgeInsets.only(right: ScreenUtil.getInstance().setSize(36)), decoration: BoxDecoration( border: Border(bottom: BorderSide(color: kLingyiGray, width: ScreenUtil.getInstance().setSize(1))) ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: <Widget>[ SizedBox( width: ScreenUtil.getInstance().setSize(150), child: Text('开始时间', style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(28), color: kLingyiText500),), ), SizedBox( width: ScreenUtil.getInstance().setSize(460), child: Text(startDate, style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(32), color: kLingyiOrange), textAlign: TextAlign.right,), ), nextPageArr() ], ), ) ), ), // 结束时间 GestureDetector( onTap: () { showModalBottomSheet( context: context, shape: RoundedRectangleBorder( borderRadius: BorderRadius.only( topLeft: Radius.circular(ScreenUtil.getInstance().setSize(16)), topRight: Radius.circular(ScreenUtil.getInstance().setSize(16)), ) ), builder: (context) { return StatefulBuilder( builder: (BuildContext context, setState) { endScrollCtr.jumpToItem(pickEndIndex); return Column( mainAxisSize: MainAxisSize.min, children: <Widget>[ Container( height: ScreenUtil.getInstance().setSize(105), alignment: Alignment.center, decoration: BoxDecoration( color: kLingyiWhite, border: Border(bottom: BorderSide(color: kLingyiGray, width: ScreenUtil.getInstance().setSize(1))) ), child: Text('结束时间', style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(32), color: kLingyiOrange),), ), Container( width: MediaQuery.of(context).size.height, height: ScreenUtil.getInstance().setSize(240), color: kLingyiWhite, padding: EdgeInsets.fromLTRB(ScreenUtil.getInstance().setSize(36), ScreenUtil.getInstance().setSize(30), ScreenUtil.getInstance().setSize(36), ScreenUtil.getInstance().setSize(30)), child: GridView.builder( gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 4, childAspectRatio: 2, crossAxisSpacing: 20, mainAxisSpacing: ScreenUtil.getInstance().setSize(30), ), itemCount: durationList.length, itemBuilder: (BuildContext context, int index) { return GestureDetector( onTap: () { // setPickDurationIndex(index); setState(() { pickDurationIndex = index; }); }, child: Container( height: ScreenUtil.getInstance().setSize(72), width: ScreenUtil.getInstance().setSize(145), decoration: BoxDecoration( borderRadius: BorderRadius.circular(ScreenUtil.getInstance().setSize(36)), border: Border.all(color: (pickDurationIndex == index) ? kLingyiGreen : kLingyiGray, width: ScreenUtil.getInstance().setSize(1)), color: (pickDurationIndex == index) ? kLingyiGreen : kLingyiWhite ), child: Stack( alignment: Alignment.center, children: <Widget>[ Text(durationList[index], style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(32), color: (pickDurationIndex == index) ? kLingyiWhite : kLingyiText500),) ], ), ) ); } ) ), Offstage( offstage: pickDurationIndex != 6, child: Container( height: ScreenUtil.getInstance().setSize(320), child: CupertinoPicker( itemExtent: ScreenUtil.getInstance().setSize(80), onSelectedItemChanged: (index) { pickEndIndex = index; }, scrollController: endScrollCtr, diameterRatio: 720.0, // 滚筒的曲率,就是弯曲的程度 useMagnifier: true, magnification: 1.0, looping: true, backgroundColor: kLingyiWhite, offAxisFraction: 100.0, // 子项的偏移 children: endDateItems.toList(), ) ), ), Container( height: ScreenUtil.getInstance().setSize(20), color: kLingyiGray100, ), Container( color: kLingyiWhite, padding: EdgeInsets.fromLTRB(ScreenUtil.getInstance().setSize(36), 0, ScreenUtil.getInstance().setSize(36), 0), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: <Widget>[ Expanded( flex: 1, child: GestureDetector( onTap: () { Navigator.pop(context); }, child: Container( height: ScreenUtil.getInstance().setSize(90), decoration: BoxDecoration( border: Border(right: BorderSide(color: kLingyiGray, width: ScreenUtil.getInstance().setSize(1))) ), alignment: Alignment.center, child: Text('取消', style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(32), color: kLingyiText100),), ), ) ), Expanded( flex: 1, child: GestureDetector( onTap: () { setEndDate(); Navigator.pop(context); }, child: Container( height: ScreenUtil.getInstance().setSize(100), alignment: Alignment.center, child: Text('确认', style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(32), color: kLingyiGreen),), ), ) ), ], ), ), Container( color: kLingyiWhite, height: ScreenUtil.bottomBarHeight, ) ], ); }, ); }, ); }, child: Container( padding: EdgeInsets.only(left: ScreenUtil.getInstance().setSize(36)), color: kLingyiWhite, child: Container( height: ScreenUtil.getInstance().setSize(100), padding: EdgeInsets.only(right: ScreenUtil.getInstance().setSize(36)), decoration: BoxDecoration( border: Border(bottom: BorderSide(color: kLingyiGray, width: ScreenUtil.getInstance().setSize(1))) ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: <Widget>[ SizedBox( width: ScreenUtil.getInstance().setSize(150), child: Text('结束时间', style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(28), color: kLingyiText500),), ), SizedBox( width: ScreenUtil.getInstance().setSize(460), child: Text(endDate, style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(32), color: kLingyiOrange), textAlign: TextAlign.right,), ), nextPageArr() ], ), ), ), ), // 重复 GestureDetector( onTap: () { showModalBottomSheet( context: context, shape: RoundedRectangleBorder( borderRadius: BorderRadius.only( topLeft: Radius.circular(ScreenUtil.getInstance().setSize(16)), topRight: Radius.circular(ScreenUtil.getInstance().setSize(16)), ) ), builder: (context) { return StatefulBuilder( builder: (BuildContext context, setState) { return Column( mainAxisSize: MainAxisSize.min, children: <Widget>[ Container( height: ScreenUtil.getInstance().setSize(105), alignment: Alignment.center, decoration: BoxDecoration( color: kLingyiWhite, border: Border(bottom: BorderSide(color: kLingyiGray, width: ScreenUtil.getInstance().setSize(1))) ), child: Text('任务频率', style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(32), color: kLingyiOrange),), ), Container( width: MediaQuery.of(context).size.height, height: ScreenUtil.getInstance().setSize(240), color: kLingyiWhite, padding: EdgeInsets.fromLTRB(ScreenUtil.getInstance().setSize(36), ScreenUtil.getInstance().setSize(30), ScreenUtil.getInstance().setSize(36), ScreenUtil.getInstance().setSize(30)), child: GridView.builder( gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 4, childAspectRatio: 2, crossAxisSpacing: 20, mainAxisSpacing: ScreenUtil.getInstance().setSize(30), ), itemCount: weekList.length, itemBuilder: (BuildContext context, int index) { return GestureDetector( onTap: () { weekList[index]['isPick'] = !weekList[index]['isPick']; if(index == weekList.length-1) { // 全选与反选 for(int i = 0, length = weekList.length-1; i < length; i++) { weekList[i]['isPick'] = weekList[index]['isPick']; } }else { // 判断是否全选 if(weekList[index]['isPick']) { weekList.last['isPick'] = true; for(int i = 0, length = weekList.length-1; i < length; i++) { if(!weekList[i]['isPick']) { weekList.last['isPick'] = false; break; } } }else { weekList.last['isPick'] = false; } } setState(() {}); }, child: Container( height: ScreenUtil.getInstance().setSize(72), padding: EdgeInsets.fromLTRB(ScreenUtil.getInstance().setSize(36), 0, ScreenUtil.getInstance().setSize(36), 0), decoration: BoxDecoration( borderRadius: BorderRadius.circular(ScreenUtil.getInstance().setSize(36)), border: Border.all(color: weekList[index]['isPick'] ? kLingyiGreen : kLingyiGray, width: ScreenUtil.getInstance().setSize(1)), color: weekList[index]['isPick'] ? kLingyiGreen : kLingyiWhite ), child: Stack( alignment: Alignment.center, children: <Widget>[ Text(weekList[index]['showValue'], style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(32), color: weekList[index]['isPick'] ? kLingyiWhite : kLingyiText500),) ], ), ) ); } ) ), Container( height: ScreenUtil.getInstance().setSize(100), color: kLingyiGray100, alignment: Alignment.center, child: RichText( text: TextSpan( children: [ TextSpan( text: '由', style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(32), color: kLingyiText100), ), TextSpan( text: startDate, style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(32), color: kLingyiOrange), ), TextSpan( text: '开始,每天坚持', style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(32), color: kLingyiText100), ), ] ), ), ), Container( color: kLingyiWhite, padding: EdgeInsets.fromLTRB(ScreenUtil.getInstance().setSize(36), 0, ScreenUtil.getInstance().setSize(36), 0), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: <Widget>[ Expanded( flex: 1, child: GestureDetector( onTap: () { Navigator.pop(context); }, child: Container( height: ScreenUtil.getInstance().setSize(90), decoration: BoxDecoration( border: Border(right: BorderSide(color: kLingyiGray, width: ScreenUtil.getInstance().setSize(1))) ), alignment: Alignment.center, child: Text('取消', style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(32), color: kLingyiText100),), ), ) ), Expanded( flex: 1, child: GestureDetector( onTap: () { setCurrentWeek(); Navigator.pop(context); }, child: Container( height: ScreenUtil.getInstance().setSize(100), alignment: Alignment.center, child: Text('确认', style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(32), color: kLingyiGreen),), ), ) ), ], ), ), Container( color: kLingyiWhite, height: ScreenUtil.bottomBarHeight, ) ], ); } ); }, ); }, child: Container( padding: EdgeInsets.only(left: ScreenUtil.getInstance().setSize(36)), color: kLingyiWhite, child: Container( height: ScreenUtil.getInstance().setSize(100), padding: EdgeInsets.only(right: ScreenUtil.getInstance().setSize(36)), decoration: BoxDecoration( border: Border(bottom: BorderSide(color: kLingyiGray, width: ScreenUtil.getInstance().setSize(1))) ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: <Widget>[ SizedBox( width: ScreenUtil.getInstance().setSize(150), child: Text('重复', style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(28), color: kLingyiText500),), ), SizedBox( width: ScreenUtil.getInstance().setSize(460), child: Text(currentWeek, style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(32), color: kLingyiText500), textAlign: TextAlign.right,), ), nextPageArr() ], ), ), ), ), // 提醒 Container( padding: EdgeInsets.only(left: ScreenUtil.getInstance().setSize(36)), color: kLingyiWhite, child: Container( height: ScreenUtil.getInstance().setSize(100), padding: EdgeInsets.only(right: ScreenUtil.getInstance().setSize(36)), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: <Widget>[ SizedBox( width: ScreenUtil.getInstance().setSize(150), child: Text('提醒', style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(28), color: kLingyiText500),), ), CupertinoSwitch( value: isWork, onChanged: (value) async { setState(() { isWork = value; }); } ), ], ), ), ), Container( padding: EdgeInsets.only(left: ScreenUtil.getInstance().setSize(36)), color: kLingyiWhite, child: Container( height: ScreenUtil.getInstance().setSize(clockList.length < 5 ? 120 : 240), padding: EdgeInsets.only(right: ScreenUtil.getInstance().setSize(12)), decoration: BoxDecoration( border: Border(bottom: BorderSide(color: kLingyiGray, width: ScreenUtil.getInstance().setSize(1))) ), child: GridView.builder( padding: EdgeInsets.only(right: ScreenUtil.getInstance().setSize(24)), gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 5, childAspectRatio: 2, crossAxisSpacing: 10, mainAxisSpacing: ScreenUtil.getInstance().setSize(30), ), itemCount: clockList.length+1, itemBuilder: (BuildContext context, int index) { if(index < clockList.length) { return GestureDetector( onTap: () { showClockPick(clockList[index]['value'], editIndex: index); }, child: Container( padding: EdgeInsets.only(top: ScreenUtil.getInstance().setSize(12)), width: ScreenUtil.getInstance().setSize(120), child: Stack( overflow: Overflow.visible, children: <Widget>[ Positioned( left: 0, top: 0, width: ScreenUtil.getInstance().setSize(120), height: ScreenUtil.getInstance().setSize(76), child: Container( width: ScreenUtil.getInstance().setSize(120), height: ScreenUtil.getInstance().setSize(76), decoration: BoxDecoration( color: Color(0xfff5f5f5), borderRadius: BorderRadius.circular(ScreenUtil.getInstance().setSize(8)) ), child: Stack( alignment: Alignment.center, children: <Widget>[ Text(clockList[index]['showValue'], style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(32), color: kLingyiText500),) ], ), ), ), Positioned( right: ScreenUtil.getInstance().setSize(-12), top: ScreenUtil.getInstance().setSize(-12), width: ScreenUtil.getInstance().setSize(36), height: ScreenUtil.getInstance().setSize(36), child: GestureDetector( onTap: () { // 删除对应闹钟 clockList.removeAt(index); setState(() {}); }, child: CircleAvatar( radius: ScreenUtil.getInstance().setSize(36), backgroundColor: kLingyiGray300, backgroundImage: getAssetImage('2_health/s_delete.png'), ) ), ) ], ), ) ); }else { return Offstage( offstage: clockList.length > 9, child: GestureDetector( onTap: () { showClockPick(0); }, child: Container( padding: EdgeInsets.only(top: ScreenUtil.getInstance().setSize(12)), width: ScreenUtil.getInstance().setSize(120), child: Stack( overflow: Overflow.visible, children: <Widget>[ Positioned( left: 0, top: 0, width: ScreenUtil.getInstance().setSize(120), height: ScreenUtil.getInstance().setSize(76), child: Container( width: ScreenUtil.getInstance().setSize(120), height: ScreenUtil.getInstance().setSize(76), decoration: BoxDecoration( color: Color(0xfff5f5f5), borderRadius: BorderRadius.circular(ScreenUtil.getInstance().setSize(8)) ), child: Stack( alignment: Alignment.center, children: <Widget>[ Image( width: ScreenUtil.getInstance().setSize(32), height: ScreenUtil.getInstance().setSize(32), fit: BoxFit.cover, image: getAssetImage('2_health/i_add.png'), ) ], ), ), ), ], ), ) ) ); } } ) ), ), // 提醒音 GestureDetector( onTap: () async{ var res = await Navigator.of(context).push( MaterialPageRoute(builder: (BuildContext context) { return AppRoute.getPage('page://health/ringing', {}); }) ); if (res != null) { print(res['info']); setState(() { ringing = res['info']; }); } }, child: Container( padding: EdgeInsets.only(left: ScreenUtil.getInstance().setSize(36)), color: kLingyiWhite, child: Container( height: ScreenUtil.getInstance().setSize(100), padding: EdgeInsets.only(right: ScreenUtil.getInstance().setSize(36)), decoration: BoxDecoration( border: Border(bottom: BorderSide(color: kLingyiGray, width: ScreenUtil.getInstance().setSize(1))) ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: <Widget>[ SizedBox( width: ScreenUtil.getInstance().setSize(150), child: Text('提醒音', style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(28), color: kLingyiText500),), ), SizedBox( width: ScreenUtil.getInstance().setSize(460), child: Text(ringing, style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(32), color: kLingyiText500), textAlign: TextAlign.right,), ), nextPageArr() ], ), ), ), ) // 更多提醒方式 // Container( // padding: EdgeInsets.only(left: ScreenUtil.getInstance().setSize(36)), // color: kLingyiWhite, // child: Container( // height: ScreenUtil.getInstance().setSize(100), // padding: EdgeInsets.only(right: ScreenUtil.getInstance().setSize(36)), // decoration: BoxDecoration( // border: Border(bottom: BorderSide(color: kLingyiGray, width: ScreenUtil.getInstance().setSize(1))) // ), // child: Row( // mainAxisAlignment: MainAxisAlignment.spaceBetween, // children: <Widget>[ // SizedBox( // width: ScreenUtil.getInstance().setSize(200), // child: Text('更多提醒方式', style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(28), color: kLingyiText500),), // ), // SizedBox( // width: ScreenUtil.getInstance().setSize(410), // child: Row( // mainAxisAlignment: MainAxisAlignment.end, // children: <Widget>[ // ClipRRect( // borderRadius: BorderRadius.circular(ScreenUtil.getInstance().setSize(8)), // child: Image( // width: ScreenUtil.getInstance().setSize(48), // height: ScreenUtil.getInstance().setSize(48), // image: getAssetImage('default.png'), // fit: BoxFit.cover, // ), // ), // SizedBox(width: ScreenUtil.getInstance().setSize(24),), // ClipRRect( // borderRadius: BorderRadius.circular(ScreenUtil.getInstance().setSize(8)), // child: Image( // width: ScreenUtil.getInstance().setSize(48), // height: ScreenUtil.getInstance().setSize(48), // image: getAssetImage('default.png'), // fit: BoxFit.cover, // ), // ), // SizedBox(width: ScreenUtil.getInstance().setSize(24),), // ClipRRect( // borderRadius: BorderRadius.circular(ScreenUtil.getInstance().setSize(8)), // child: Image( // width: ScreenUtil.getInstance().setSize(48), // height: ScreenUtil.getInstance().setSize(48), // image: getAssetImage('default.png'), // fit: BoxFit.cover, // ), // ), // ], // ), // ), // nextPageArr() // ], // ), // ), // ) ], ) ) ); }}
封装空列表呈现组件
import 'package:flutter/material.dart';import 'package:lingyi/config/color.dart';import 'package:lingyi/util/common.dart';class Nothing extends StatelessWidget { final String title; final double height; final Color bgColor; final bool isLoading; Nothing(this.title, {this.height, this.bgColor, this.isLoading=false}); @override Widget build(BuildContext context) { return Container( padding: EdgeInsets.only(bottom: ScreenUtil.getInstance().setSize(100)), width: MediaQuery.of(context).size.width, height: height ?? MediaQuery.of(context).size.height, decoration: BoxDecoration( color: bgColor ?? kLingyiGray100 ), alignment: Alignment.center, child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: <Widget>[ isLoading ? Image(image: getAssetImage('1_circle/loading.png'), width: ScreenUtil.getInstance().setSize(380), fit: BoxFit.fitWidth,) : Image(image: getAssetImage('5_public/default.png'), width: ScreenUtil.getInstance().setSize(420), fit: BoxFit.fitWidth,), SizedBox(width: ScreenUtil.getInstance().setSize(30)), Offstage( offstage: isLoading, child: Text(title, style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(28), color: kLingyiText100),) ) ], ), ); }}
安全区域的使用
1. 弹窗使用ScreenUtil.bottomBarHeight在底部增加高度2. 使用SafeArea组件包括整个应用
根页面返回键退出App处理
使用 WillPopScope 组件包括入口组件Future<bool> _onWillPop() async { ShowAlert.show(context, '确定退出应用吗?', onConfirm: () { SystemNavigator.pop();});return false;}
webView 页面友好处理
import 'package:flutter/material.dart';import 'package:webview_flutter/webview_flutter.dart';import 'package:annotation_route/route.dart';import 'package:lingyi/config/color.dart';@ARoute(url: 'page://webview')class Webview extends StatefulWidget { final dynamic option; Webview(this.option); @override WebviewState createState() => WebviewState();}class WebviewState extends State<Webview> { bool isLoading = true; @override Widget build(BuildContext context) { String url = widget.option.query['url']; String title = widget.option.query['title']; return Scaffold( appBar: AppBar( title: Text(title), leading: goBackArr(context), bottom: PreferredSize( preferredSize: Size.fromHeight(ScreenUtil.getInstance().setSize(4)), child: Offstage( offstage: !isLoading, child: SizedBox( height: ScreenUtil.getInstance().setSize(4), width: MediaQuery.of(context).size.width, child: LinearProgressIndicator(), ), ), ), ), body: WebView( onWebViewCreated: (WebViewController web) { setState(() { isLoading = true; }); }, onPageFinished: (String value) { setState(() { isLoading = false; }); }, initialUrl: url, javascriptMode: JavascriptMode.unrestricted, ), ); }}
pdf 预览功能
import 'dart:async';import 'dart:io';import 'package:flutter/foundation.dart';import 'package:flutter/material.dart';import 'package:flutter_full_pdf_viewer/full_pdf_viewer_scaffold.dart';import 'package:path_provider/path_provider.dart';import 'package:annotation_route/route.dart';import 'package:lingyi/config/color.dart';import 'package:lingyi/util/common.dart';// import 'package:flutter/services.dart' show rootBundle;// import 'dart:typed_data';@ARoute(url: 'page://pdfview')class Pdfview extends StatefulWidget { final dynamic option; Pdfview(this.option); @override PdfviewState createState() => new PdfviewState();}class PdfviewState extends State<Pdfview> { String pathPDF = ""; @override void initState() { super.initState(); createFileOfPdfUrl().then((f) { print(f.toString()); setState(() { pathPDF = f.path; print(pathPDF); }); }); } Future<File> createFileOfPdfUrl() async { final url = "http://africau.edu/images/default/sample.pdf"; final filename = url.substring(url.lastIndexOf("/") + 1); var request = await HttpClient().getUrl(Uri.parse(url)); var response = await request.close(); var bytes = await consolidateHttpClientResponseBytes(response); String dir = (await getApplicationDocumentsDirectory()).path; File file = new File('$dir/$filename'); await file.writeAsBytes(bytes); return file; } // @override // void initState() { // super.initState(); // print('init'); // printFile(); // createFileOfPdfUrl().then((f) { // setState(() { // pathPDF = f.path; // print(pathPDF); // }); // }); // } // void printFile() async { // var filebd = await rootBundle.load("assets/data/cannon.pdf"); // print(filebd.runtimeType); // } // Future<void> writeToFile(ByteData data, String path) { // final buffer = data.buffer; // return new File(path).writeAsBytes( // buffer.asUint8List(data.offsetInBytes, data.lengthInBytes)); // } // Future<File> createFileOfPdfUrl() async { // final filename = 'test.pdf'; // var bytes = await rootBundle.load("assets/data/cannon.pdf"); // String dir = (await getApplicationDocumentsDirectory()).path; // writeToFile(bytes,'$dir/$filename'); // File file = new File('$dir/$filename'); // return file; // } @override Widget build(BuildContext context) { return pathPDF.isEmpty ? Scaffold( appBar: AppBar( title: Text("Document"), ), body: Container( padding: EdgeInsets.only(bottom: ScreenUtil.getInstance().setSize(100)), width: MediaQuery.of(context).size.width, height: MediaQuery.of(context).size.height, decoration: BoxDecoration( color: kLingyiGray100 ), alignment: Alignment.center, child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: <Widget>[ Image(image: getAssetImage('5_public/default.png'), width: ScreenUtil.getInstance().setSize(420), fit: BoxFit.fitWidth,), SizedBox(width: ScreenUtil.getInstance().setSize(30)), Text('加载中...', style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(28), color: kLingyiText100),) ], ), ) ) : PDFViewerScaffold( appBar: AppBar( title: Text("Document"), ), path: pathPDF ); }}