使用 Material 的 ShowDialog 组件自定义弹窗

  1. void showComfirm(BuildContext context, String msg,
  2. {Function comfirm,
  3. Function cancel,
  4. String comfirmTitle = '确认',
  5. String cancelTitle = '取消'}) {
  6. showDialog(
  7. context: context,
  8. builder: (BuildContext context) {
  9. return CustomDialog(
  10. backgroundColor: Color(0xffffffff),
  11. shape: RoundedRectangleBorder(
  12. borderRadius:
  13. BorderRadius.circular(ScreenUtil.getInstance().setSize(16))),
  14. minWidth: ScreenUtil.getInstance().setSize(480),
  15. maxWidth: ScreenUtil.getInstance().setSize(480),
  16. minHeight: ScreenUtil.getInstance().setSize(240),
  17. child: Column(
  18. mainAxisAlignment: MainAxisAlignment.start,
  19. crossAxisAlignment: CrossAxisAlignment.center,
  20. mainAxisSize: MainAxisSize.min,
  21. children: <Widget>[
  22. Container(
  23. constraints: BoxConstraints(
  24. minHeight: ScreenUtil.getInstance().setSize(150),
  25. ),
  26. decoration: BoxDecoration(
  27. border: Border(
  28. bottom: BorderSide(
  29. color: kLingyiGray,
  30. width: ScreenUtil.getInstance().setSize(1),
  31. ))),
  32. width: ScreenUtil.getInstance().setSize(480),
  33. padding: EdgeInsets.fromLTRB(
  34. ScreenUtil.getInstance().setSize(34),
  35. ScreenUtil.getInstance().setSize(34),
  36. ScreenUtil.getInstance().setSize(34),
  37. ScreenUtil.getInstance().setSize(34)),
  38. child: Text(
  39. msg,
  40. style: TextStyle(
  41. fontSize: ScreenUtil.getInstance().setSp(32),
  42. color: kLingyiText500),
  43. ),
  44. ),
  45. Container(
  46. height: ScreenUtil.getInstance().setSize(88),
  47. child: Flex(
  48. direction: Axis.horizontal,
  49. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  50. crossAxisAlignment: CrossAxisAlignment.center,
  51. children: <Widget>[
  52. Expanded(
  53. flex: 1,
  54. child: GestureDetector(
  55. onTap: () {
  56. Navigator.of(context).pop();
  57. if (cancel != null) cancel();
  58. },
  59. child: Text(
  60. cancelTitle,
  61. style: TextStyle(
  62. fontSize: ScreenUtil.getInstance().setSp(28),
  63. color: Color(0xff999999)),
  64. textAlign: TextAlign.center,
  65. ),
  66. )),
  67. Container(
  68. width: ScreenUtil.getInstance().setSize(1),
  69. height: ScreenUtil.getInstance().setSize(88),
  70. color: kLingyiGray,
  71. ),
  72. Expanded(
  73. flex: 1,
  74. child: GestureDetector(
  75. onTap: () {
  76. Navigator.of(context).pop();
  77. if (comfirm != null) comfirm();
  78. },
  79. child: Text(
  80. comfirmTitle,
  81. style: TextStyle(
  82. fontSize: ScreenUtil.getInstance().setSp(28),
  83. color: Color(0xff4499ff)),
  84. textAlign: TextAlign.center,
  85. ),
  86. ))
  87. ],
  88. ),
  89. ),
  90. ],
  91. ),
  92. );
  93. });
  94. }
  95. void showAlert(BuildContext context, String msg,
  96. {Function callback, String comfirmTitle = '确认'}) {
  97. showDialog(
  98. context: context,
  99. builder: (BuildContext context) {
  100. return CustomDialog(
  101. backgroundColor: Color(0xffffffff),
  102. shape: RoundedRectangleBorder(
  103. borderRadius:
  104. BorderRadius.circular(ScreenUtil.getInstance().setSize(16))),
  105. minWidth: ScreenUtil.getInstance().setSize(480),
  106. maxWidth: ScreenUtil.getInstance().setSize(480),
  107. minHeight: ScreenUtil.getInstance().setSize(240),
  108. child: Column(
  109. mainAxisAlignment: MainAxisAlignment.start,
  110. crossAxisAlignment: CrossAxisAlignment.center,
  111. mainAxisSize: MainAxisSize.min,
  112. children: <Widget>[
  113. Container(
  114. constraints: BoxConstraints(
  115. minHeight: ScreenUtil.getInstance().setSize(150),
  116. ),
  117. width: ScreenUtil.getInstance().setSize(480),
  118. decoration: BoxDecoration(
  119. border: Border(
  120. bottom: BorderSide(
  121. color: kLingyiGray,
  122. width: ScreenUtil.getInstance().setSize(1),
  123. ))),
  124. padding: EdgeInsets.fromLTRB(
  125. ScreenUtil.getInstance().setSize(34),
  126. ScreenUtil.getInstance().setSize(34),
  127. ScreenUtil.getInstance().setSize(34),
  128. ScreenUtil.getInstance().setSize(34)),
  129. child: Text(
  130. msg,
  131. style: TextStyle(
  132. fontSize: ScreenUtil.getInstance().setSp(32),
  133. color: kLingyiText500),
  134. textAlign: TextAlign.center,
  135. ),
  136. ),
  137. GestureDetector(
  138. onTap: () {
  139. Navigator.of(context).pop();
  140. if (callback != null) callback();
  141. },
  142. child: Container(
  143. height: ScreenUtil.getInstance().setSize(88),
  144. alignment: Alignment.center,
  145. child: Text(
  146. comfirmTitle,
  147. style: TextStyle(
  148. fontSize: ScreenUtil.getInstance().setSp(28),
  149. color: Color(0xff4499ff)),
  150. ),
  151. ),
  152. )
  153. ],
  154. ),
  155. );
  156. });
  157. }
  158. void showToast(BuildContext context, String msg,
  159. {Function callback, int duration = 1500, bool isSuccess = true}) {
  160. Timer(Duration(milliseconds: duration), () {
  161. Navigator.pop(context);
  162. if (callback != null) callback();
  163. });
  164. customShowDialog(
  165. context: context,
  166. barrierDismissible: false,
  167. barrierColor: Color(0x00ffffff),
  168. builder: (BuildContext context) {
  169. return CustomDialog(
  170. backgroundColor: Color(0x88000000),
  171. shape: RoundedRectangleBorder(
  172. borderRadius: BorderRadius.circular(
  173. ScreenUtil.getInstance().setSize(12))),
  174. elevation: 0,
  175. child: Padding(
  176. padding: EdgeInsets.fromLTRB(20, 15, 20, 15),
  177. child: Column(
  178. mainAxisAlignment: MainAxisAlignment.center,
  179. crossAxisAlignment: CrossAxisAlignment.center,
  180. mainAxisSize: MainAxisSize.min,
  181. children: <Widget>[
  182. Icon(
  183. isSuccess ? Icons.done : Icons.error,
  184. size: ScreenUtil.getInstance().setSize(80),
  185. color: kLingyiWhite,
  186. ),
  187. SizedBox(
  188. height: ScreenUtil.getInstance().setSize(20),
  189. ),
  190. Text(
  191. msg,
  192. style: TextStyle(
  193. color: kLingyiWhite,
  194. fontSize: ScreenUtil.getInstance().setSp(28)),
  195. textAlign: TextAlign.center,
  196. maxLines: 3,
  197. overflow: TextOverflow.ellipsis,
  198. )
  199. ],
  200. ),
  201. ));
  202. });
  203. }
  204. void showMsg(BuildContext context, String msg,
  205. {int duration = 1500, Function callback}) {
  206. Timer(Duration(milliseconds: duration), () {
  207. Navigator.of(context).pop();
  208. if (callback != null) callback();
  209. });
  210. customShowDialog(
  211. context: context,
  212. barrierDismissible: false,
  213. barrierColor: Color(0x00ffffff),
  214. builder: (BuildContext context) {
  215. return CustomDialog(
  216. backgroundColor: Color(0x88000000),
  217. shape: RoundedRectangleBorder(
  218. borderRadius:
  219. BorderRadius.circular(ScreenUtil.getInstance().setSize(8))),
  220. elevation: 0,
  221. minWidth: ScreenUtil.getInstance().setSize(300),
  222. maxWidth: ScreenUtil.getInstance().setSize(650),
  223. minHeight: ScreenUtil.getInstance().setSize(64),
  224. child: Stack(
  225. alignment: Alignment.center,
  226. children: <Widget>[
  227. Padding(
  228. padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
  229. child: Text(
  230. msg,
  231. style: TextStyle(
  232. color: kLingyiWhite,
  233. fontSize: ScreenUtil.getInstance().setSp(28)),
  234. textAlign: TextAlign.center,
  235. maxLines: 2,
  236. overflow: TextOverflow.ellipsis,
  237. ),
  238. )
  239. ],
  240. ));
  241. });
  242. }
  243. class CustomDialog extends StatelessWidget {
  244. const CustomDialog({
  245. Key key,
  246. this.backgroundColor,
  247. this.elevation,
  248. this.insetAnimationDuration = const Duration(milliseconds: 100),
  249. this.insetAnimationCurve = Curves.decelerate,
  250. this.shape,
  251. this.child,
  252. this.minWidth,
  253. this.maxWidth,
  254. this.minHeight,
  255. this.maxHeight,
  256. }) : super(key: key);
  257. final Color backgroundColor;
  258. final double elevation;
  259. final Duration insetAnimationDuration;
  260. final Curve insetAnimationCurve;
  261. final ShapeBorder shape;
  262. final Widget child;
  263. final double minWidth;
  264. final double maxWidth;
  265. final double minHeight;
  266. final double maxHeight;
  267. static const RoundedRectangleBorder _defaultDialogShape =
  268. RoundedRectangleBorder(
  269. borderRadius: BorderRadius.all(Radius.circular(2.0)));
  270. static const double _defaultElevation = 24.0;
  271. @override
  272. Widget build(BuildContext context) {
  273. final DialogTheme dialogTheme = DialogTheme.of(context);
  274. return AnimatedPadding(
  275. padding: MediaQuery.of(context).viewInsets +
  276. const EdgeInsets.symmetric(horizontal: 0, vertical: 0),
  277. duration: insetAnimationDuration,
  278. curve: insetAnimationCurve,
  279. child: MediaQuery.removeViewInsets(
  280. removeLeft: true,
  281. removeTop: true,
  282. removeRight: true,
  283. removeBottom: true,
  284. context: context,
  285. child: Center(
  286. child: ConstrainedBox(
  287. constraints: BoxConstraints(
  288. minWidth: minWidth ?? ScreenUtil.getInstance().setSize(200),
  289. minHeight: minHeight ?? ScreenUtil.getInstance().setSize(200),
  290. maxWidth: maxWidth ?? ScreenUtil.getInstance().setSize(600),
  291. maxHeight: maxWidth ?? ScreenUtil.getInstance().setSize(600),
  292. ),
  293. child: Material(
  294. color: backgroundColor ??
  295. dialogTheme.backgroundColor ??
  296. Theme.of(context).dialogBackgroundColor,
  297. elevation:
  298. elevation ?? dialogTheme.elevation ?? _defaultElevation,
  299. shape: shape ?? dialogTheme.shape ?? _defaultDialogShape,
  300. type: MaterialType.card,
  301. child: child,
  302. ),
  303. ),
  304. ),
  305. ),
  306. );
  307. }
  308. }
  309. Future<T> customShowDialog<T>({
  310. @required
  311. BuildContext context,
  312. bool barrierDismissible = true,
  313. Color barrierColor = Colors.black54,
  314. @Deprecated(
  315. 'Instead of using the "child" argument, return the child from a closure '
  316. 'provided to the "builder" argument. This will ensure that the BuildContext '
  317. 'is appropriate for widgets built in the dialog.')
  318. Widget child,
  319. WidgetBuilder builder,
  320. }) {
  321. assert(child == null || builder == null);
  322. assert(debugCheckHasMaterialLocalizations(context));
  323. final ThemeData theme = Theme.of(context, shadowThemeOnly: true);
  324. return showGeneralDialog(
  325. context: context,
  326. pageBuilder: (BuildContext buildContext, Animation<double> animation,
  327. Animation<double> secondaryAnimation) {
  328. final Widget pageChild = child ?? Builder(builder: builder);
  329. return SafeArea(
  330. child: Builder(builder: (BuildContext context) {
  331. return theme != null
  332. ? Theme(data: theme, child: pageChild)
  333. : pageChild;
  334. }),
  335. );
  336. },
  337. barrierDismissible: barrierDismissible,
  338. barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel,
  339. barrierColor: barrierColor,
  340. transitionDuration: const Duration(milliseconds: 150),
  341. transitionBuilder: _buildMaterialDialogTransitions,
  342. );
  343. }
  344. Widget _buildMaterialDialogTransitions(
  345. BuildContext context,
  346. Animation<double> animation,
  347. Animation<double> secondaryAnimation,
  348. Widget child) {
  349. return FadeTransition(
  350. opacity: CurvedAnimation(
  351. parent: animation,
  352. curve: Curves.easeOut,
  353. ),
  354. child: child,
  355. );
  356. }

使用 Material 的 OverlayEntry组件自定义弹窗

  1. import 'package:flutter/material.dart';
  2. import 'package:flutter/widgets.dart';
  3. import 'package:lingyi/config/color.dart';
  4. class ShowMsg {
  5. static void show(BuildContext context, String msg ,{
  6. int duration = 1500,
  7. int gravity = 1,
  8. Color backgroundColor = const Color(0x88000000),
  9. Color textColor = Colors.white,
  10. double backgroundRadius,
  11. Border border,
  12. Function callback
  13. }) {
  14. MsgView.dismiss();
  15. ToastView.dismiss();
  16. MsgView.createView(
  17. msg, context, duration, gravity, backgroundColor, textColor, backgroundRadius, border, callback);
  18. }
  19. }
  20. class MsgView {
  21. static final MsgView _singleton = new MsgView._internal();
  22. factory MsgView() {
  23. return _singleton;
  24. }
  25. MsgView._internal();
  26. static OverlayState overlayState;
  27. static OverlayEntry _overlayEntry;
  28. static bool _isVisible = false;
  29. static void createView(String msg, BuildContext context, int duration, int gravity,
  30. Color background, Color textColor, double backgroundRadius, Border border, Function callback) async {
  31. overlayState = Overlay.of(context);
  32. _overlayEntry = new OverlayEntry(
  33. builder: (BuildContext context) => PositionWidget(
  34. widget: Container(
  35. width: MediaQuery.of(context).size.width,
  36. child: Container(
  37. alignment: Alignment.center,
  38. width: MediaQuery.of(context).size.width,
  39. child: Container(
  40. decoration: BoxDecoration(
  41. color: background,
  42. borderRadius: BorderRadius.circular(backgroundRadius ?? ScreenUtil.getInstance().setSize(8)),
  43. border: border,
  44. ),
  45. constraints: BoxConstraints(
  46. minWidth: ScreenUtil.getInstance().setSize(300),
  47. maxWidth: ScreenUtil.getInstance().setSize(650),
  48. minHeight: ScreenUtil.getInstance().setSize(64),
  49. ),
  50. margin: EdgeInsets.symmetric(horizontal: 20),
  51. padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
  52. child: Stack(
  53. alignment: Alignment.center,
  54. children: <Widget>[
  55. Text(msg, softWrap: true, style: TextStyle(fontSize: ScreenUtil.getInstance().setSize(28), color: textColor)),
  56. ]
  57. )
  58. )),
  59. ),
  60. gravity: gravity),
  61. );
  62. _isVisible = true;
  63. overlayState.insert(_overlayEntry);
  64. await new Future.delayed(Duration(milliseconds: duration ?? 2000));
  65. if(callback != null) callback();
  66. dismiss();
  67. }
  68. static dismiss() async {
  69. if (!_isVisible) {
  70. return;
  71. }
  72. _isVisible = false;
  73. _overlayEntry?.remove();
  74. }
  75. }
  76. class PositionWidget extends StatelessWidget {
  77. PositionWidget({
  78. Key key,
  79. @required this.widget,
  80. @required this.gravity,
  81. }) : super(key: key);
  82. final Widget widget;
  83. final int gravity;
  84. @override
  85. Widget build(BuildContext context) {
  86. return new Positioned(
  87. top: gravity == 2 ? 50 : null,
  88. bottom: gravity == 0 ? 50 : null,
  89. child: Material(
  90. color: Colors.transparent,
  91. child: widget,
  92. ));
  93. }
  94. }
  95. // show Tost----------------------------------------------
  96. class ShowToast {
  97. static void show(BuildContext context, String msg ,{
  98. bool isSuccess = true,
  99. int duration = 1500,
  100. Color backgroundColor,
  101. Color textColor = Colors.white,
  102. double backgroundRadius,
  103. Function callback
  104. }) {
  105. MsgView.dismiss();
  106. ToastView.dismiss();
  107. ToastView.createView(
  108. msg, context, isSuccess, duration, backgroundColor, textColor, backgroundRadius, callback);
  109. }
  110. }
  111. class ToastView {
  112. static final ToastView _singleton = new ToastView._internal();
  113. factory ToastView() {
  114. return _singleton;
  115. }
  116. ToastView._internal();
  117. static OverlayState overlayState;
  118. static OverlayEntry _overlayEntry;
  119. static bool _isVisible = false;
  120. static void createView(String msg, BuildContext context, bool isSuccess, int duration, Color background, Color textColor, double backgroundRadius, Function callback) async {
  121. overlayState = Overlay.of(context);
  122. _overlayEntry = new OverlayEntry(
  123. builder: (BuildContext context) => PositionWidget(
  124. widget: Stack(
  125. alignment: Alignment.center,
  126. children: <Widget>[
  127. Container(
  128. decoration: BoxDecoration(
  129. color: background ?? Color(0x88000000),
  130. borderRadius: BorderRadius.circular(backgroundRadius ?? ScreenUtil.getInstance().setSize(12))
  131. ),
  132. padding: EdgeInsets.fromLTRB(20, 10, 20, 10),
  133. child: Column(
  134. mainAxisAlignment: MainAxisAlignment.center,
  135. crossAxisAlignment: CrossAxisAlignment.center,
  136. mainAxisSize: MainAxisSize.min,
  137. children: <Widget>[
  138. Icon(
  139. isSuccess ? Icons.done : Icons.error,
  140. size: ScreenUtil.getInstance().setSize(80),
  141. color: textColor,
  142. ),
  143. SizedBox(
  144. height: ScreenUtil.getInstance().setSize(10),
  145. ),
  146. Text(
  147. msg,
  148. style: TextStyle(
  149. color: textColor,
  150. fontSize: ScreenUtil.getInstance().setSp(28)),
  151. textAlign: TextAlign.center,
  152. maxLines: 3,
  153. overflow: TextOverflow.ellipsis,
  154. )
  155. ],
  156. ),
  157. )
  158. ],
  159. ),
  160. gravity: 1),
  161. );
  162. _isVisible = true;
  163. overlayState.insert(_overlayEntry);
  164. await new Future.delayed(Duration(milliseconds: duration ?? 2000));
  165. if(callback != null) callback();
  166. dismiss();
  167. }
  168. static dismiss() async {
  169. if (!_isVisible) {
  170. return;
  171. }
  172. _isVisible = false;
  173. _overlayEntry?.remove();
  174. }
  175. }
  176. // show Alert---------------------------------------------
  177. class ShowAlert {
  178. static void show(BuildContext context, String msg ,{
  179. Color backgroundColor,
  180. double backgroundRadius,
  181. bool showCancel: true,
  182. String comfirmTitle: '确认',
  183. String cancelTitle: '取消',
  184. Function onConfirm,
  185. Function onCancel
  186. }) {
  187. MsgView.dismiss();
  188. ToastView.dismiss();
  189. AlertView.dismiss();
  190. AlertView.createView(msg, context, backgroundColor, backgroundRadius, showCancel, comfirmTitle, cancelTitle, onConfirm, onCancel);
  191. }
  192. }
  193. class AlertView {
  194. static final AlertView _singleton = new AlertView._internal();
  195. factory AlertView() {
  196. return _singleton;
  197. }
  198. AlertView._internal();
  199. static OverlayState overlayState;
  200. static OverlayEntry _overlayEntry;
  201. static bool _isVisible = false;
  202. static void createView(String msg, BuildContext context, Color backgroundColor, double backgroundRadius, bool showCancel, String comfirmTitle, String cancelTitle, Function onConfirm, Function onCancel) async {
  203. overlayState = Overlay.of(context);
  204. _overlayEntry = new OverlayEntry(
  205. builder: (BuildContext context) => PositionWidget(
  206. widget: Container(
  207. color: Color(0x66000000),
  208. child: Stack(
  209. alignment: Alignment.center,
  210. children: <Widget>[
  211. Container(
  212. decoration: BoxDecoration(
  213. color: backgroundColor ?? Colors.white,
  214. borderRadius: BorderRadius.circular(backgroundRadius ?? ScreenUtil.getInstance().setSize(16))
  215. ),
  216. constraints: BoxConstraints(
  217. minWidth: ScreenUtil.getInstance().setSize(480),
  218. maxWidth: ScreenUtil.getInstance().setSize(480),
  219. minHeight: ScreenUtil.getInstance().setSize(240),
  220. ),
  221. padding: EdgeInsets.fromLTRB(0, 10, 0, 10),
  222. child: Column(
  223. mainAxisAlignment: MainAxisAlignment.start,
  224. crossAxisAlignment: CrossAxisAlignment.center,
  225. mainAxisSize: MainAxisSize.min,
  226. children: <Widget>[
  227. Container(
  228. constraints: BoxConstraints(
  229. minHeight: ScreenUtil.getInstance().setSize(150),
  230. ),
  231. decoration: BoxDecoration(
  232. border: Border(
  233. bottom: BorderSide(
  234. color: kLingyiGray,
  235. width: ScreenUtil.getInstance().setSize(1),
  236. ))),
  237. width: ScreenUtil.getInstance().setSize(480),
  238. padding: EdgeInsets.fromLTRB(
  239. ScreenUtil.getInstance().setSize(34),
  240. ScreenUtil.getInstance().setSize(34),
  241. ScreenUtil.getInstance().setSize(34),
  242. ScreenUtil.getInstance().setSize(34)),
  243. child: Text(
  244. msg,
  245. style: TextStyle(
  246. fontSize: ScreenUtil.getInstance().setSp(32),
  247. color: kLingyiText500),
  248. ),
  249. ),
  250. Container(
  251. height: ScreenUtil.getInstance().setSize(88),
  252. child: !showCancel ?
  253. GestureDetector(
  254. onTap: () {
  255. dismiss();
  256. if (onConfirm != null) onConfirm();
  257. },
  258. child: Center(
  259. child: Text(
  260. comfirmTitle,
  261. style: TextStyle(
  262. fontSize: ScreenUtil.getInstance().setSp(28),
  263. color: Color(0xff4499ff)),
  264. textAlign: TextAlign.center,
  265. )
  266. ),
  267. ) : Flex(
  268. direction: Axis.horizontal,
  269. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  270. crossAxisAlignment: CrossAxisAlignment.center,
  271. children: <Widget>[
  272. Expanded(
  273. flex: 1,
  274. child: GestureDetector(
  275. onTap: () {
  276. dismiss();
  277. if (onCancel != null) onCancel();
  278. },
  279. child: Text(
  280. cancelTitle,
  281. style: TextStyle(
  282. fontSize: ScreenUtil.getInstance().setSp(28),
  283. color: Color(0xff999999)),
  284. textAlign: TextAlign.center,
  285. ),
  286. )
  287. ),
  288. Container(
  289. width: ScreenUtil.getInstance().setSize(1),
  290. height: ScreenUtil.getInstance().setSize(88),
  291. color: kLingyiGray,
  292. ),
  293. Expanded(
  294. flex: 1,
  295. child: GestureDetector(
  296. onTap: () {
  297. dismiss();
  298. if (onConfirm != null) onConfirm();
  299. },
  300. child: Text(
  301. comfirmTitle,
  302. style: TextStyle(
  303. fontSize: ScreenUtil.getInstance().setSp(28),
  304. color: Color(0xff4499ff)),
  305. textAlign: TextAlign.center,
  306. ),
  307. )
  308. )
  309. ],
  310. ),
  311. ),
  312. ],
  313. ),
  314. )
  315. ],
  316. ),
  317. ),
  318. gravity: 1),
  319. );
  320. _isVisible = true;
  321. overlayState.insert(_overlayEntry);
  322. }
  323. static dismiss() async {
  324. if (!_isVisible) {
  325. return;
  326. }
  327. _isVisible = false;
  328. _overlayEntry?.remove();
  329. }
  330. }

使用 Material 的 showModalBottomSheet 和 Cupertino 的 CupertinoPicker 制作底部抽屉选择器

  1. import 'package:flutter/cupertino.dart';
  2. import 'package:flutter/material.dart';
  3. import 'package:annotation_route/route.dart';
  4. import 'package:lingyi/config/color.dart';
  5. import 'package:lingyi/route/route.dart';
  6. import 'package:lingyi/util/common.dart';
  7. @ARoute(url: 'page://health/medicine')
  8. class Medicine extends StatefulWidget {
  9. final dynamic option;
  10. Medicine(this.option);
  11. @override
  12. MedicineState createState() => MedicineState();
  13. }
  14. class MedicineState extends State<Medicine> {
  15. bool isWork = true; // 是否提醒
  16. List<Map> startList = [];
  17. List<Map> endList = [];
  18. 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': '每天'}];
  19. List<String> durationList = ['7天','30天','90天','180天','365天',' 无期限','自定义'];
  20. String startDate = '';
  21. String endDate = '选择周期';
  22. String currentWeek = '请选择';
  23. String ringing = '默认铃声';
  24. int pickDateIndex = 0; // 选择开始时间下标
  25. int pickWeekIndex = 7; // 选择重复下标
  26. int pickDurationIndex = -1; // 选择周期时间下标
  27. int pickEndIndex = 0; // 选择自定义周期下标
  28. int pickHourIndex = 0; // 选择自定义周期下标
  29. int pickMinuteIndex = 0; // 选择自定义周期下标
  30. // List<Map> clockList = [{'showValue': '08:00', 'value': 480}, {'showValue': '09:30', 'value': 570}]; // 提醒闹钟列表
  31. List<Map> clockList = []; // 提醒闹钟列表
  32. List<String> hourList = [];
  33. List<String> minuteList = [];
  34. FixedExtentScrollController startScrollCtr = new FixedExtentScrollController();
  35. FixedExtentScrollController endScrollCtr = new FixedExtentScrollController();
  36. FixedExtentScrollController hourScrollCtr = new FixedExtentScrollController();
  37. FixedExtentScrollController minuteScrollCtr = new FixedExtentScrollController();
  38. // 今天的时间
  39. var today = new DateTime.now();
  40. String formatDate(DateTime date) {
  41. return date.year.toString() + '年' + date.month.toString() + '月' + date.day.toString() + '日 星期' + getWeekday(date.weekday);
  42. }
  43. String getWeekday(int num) {
  44. switch(num) {
  45. case 1:
  46. return '一';
  47. break;
  48. case 2:
  49. return '二';
  50. break;
  51. case 3:
  52. return '三';
  53. break;
  54. case 4:
  55. return '四';
  56. break;
  57. case 5:
  58. return '五';
  59. break;
  60. case 6:
  61. return '六';
  62. break;
  63. default:
  64. return '日';
  65. break;
  66. }
  67. }
  68. void createStartDateList() {
  69. for(int i = 0; i < 90; i++ ) {
  70. var tempDay = today.add(new Duration(days: i));
  71. Map tempObj = {'value': tempDay, 'showValue': formatDate(tempDay)};
  72. startList.add(tempObj);
  73. }
  74. createEndDateList(today);
  75. setState(() {
  76. startDate = formatDate(today);
  77. });
  78. }
  79. void createEndDateList(DateTime start) {
  80. endList = [];
  81. for(int i = 0; i < 366; i++) {
  82. var tempDay = start.add(new Duration(days: i));
  83. Map tempObj = {'value': tempDay, 'showValue': formatDate(tempDay)};
  84. endList.add(tempObj);
  85. }
  86. }
  87. void createHourList() {
  88. for(int i = 0; i < 24; i++) {
  89. hourList.add(i.toString().padLeft(2, '0'));
  90. }
  91. }
  92. void createMinuteList() {
  93. for(int i = 0; i < 60; i++) {
  94. minuteList.add(i.toString().padLeft(2, '0'));
  95. }
  96. }
  97. @override
  98. void initState() {
  99. super.initState();
  100. createStartDateList();
  101. createHourList();
  102. createMinuteList();
  103. }
  104. Iterable<Widget> get startDateItems sync* {
  105. for(int i = 0, length = startList.length; i < length; i++) {
  106. yield Container(
  107. height: ScreenUtil.getInstance().setSize(80),
  108. alignment: Alignment.center,
  109. child: Text(startList[i]['showValue'], style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(36), color: kLingyiText500)),
  110. );
  111. }
  112. }
  113. Iterable<Widget> get endDateItems sync* {
  114. for(int i = 0, length = endList.length; i < length; i++) {
  115. yield Container(
  116. height: ScreenUtil.getInstance().setSize(80),
  117. alignment: Alignment.center,
  118. child: Text(endList[i]['showValue'], style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(36), color: kLingyiText500)),
  119. );
  120. }
  121. }
  122. Iterable<Widget> get hourItems sync* {
  123. for(int i = 0, length = hourList.length; i < length; i++) {
  124. yield Container(
  125. height: ScreenUtil.getInstance().setSize(80),
  126. alignment: Alignment.center,
  127. child: Text(hourList[i], style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(36), color: kLingyiText500)),
  128. );
  129. }
  130. }
  131. Iterable<Widget> get minuteItems sync* {
  132. for(int i = 0, length = minuteList.length; i < length; i++) {
  133. yield Container(
  134. height: ScreenUtil.getInstance().setSize(80),
  135. alignment: Alignment.center,
  136. child: Text(minuteList[i], style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(36), color: kLingyiText500)),
  137. );
  138. }
  139. }
  140. void setCurrentWeek() {
  141. // 判断是否是全选
  142. if(weekList.last['isPick']) {
  143. setState(() {
  144. currentWeek = '每天';
  145. });
  146. }else {
  147. var tempList = [];
  148. weekList.forEach((value) {
  149. if(value['isPick']) {
  150. tempList.add(value['showValue']);
  151. }
  152. });
  153. setState(() {
  154. currentWeek = tempList.isEmpty ? '请选择' : tempList.join(',');
  155. });
  156. }
  157. }
  158. void setEndDate() {
  159. var tempString = '';
  160. switch(pickDurationIndex) {
  161. case 0:
  162. tempString = formatDate(startList[pickDateIndex]['value'].add(new Duration(days: 7)));
  163. break;
  164. case 1:
  165. tempString = formatDate(startList[pickDateIndex]['value'].add(new Duration(days: 30)));
  166. break;
  167. case 2:
  168. tempString = formatDate(startList[pickDateIndex]['value'].add(new Duration(days: 90)));
  169. break;
  170. case 3:
  171. tempString = formatDate(startList[pickDateIndex]['value'].add(new Duration(days: 180)));
  172. break;
  173. case 4:
  174. tempString = formatDate(startList[pickDateIndex]['value'].add(new Duration(days: 365)));
  175. break;
  176. case 5:
  177. tempString = '无期限';
  178. break;
  179. default:
  180. tempString = endList[pickEndIndex]['showValue'];
  181. break;
  182. }
  183. setState(() {
  184. endDate = tempString;
  185. });
  186. }
  187. void showClockPick(int value, {int editIndex=-1}) {
  188. // 初始化
  189. pickHourIndex = 0;
  190. pickMinuteIndex = 0;
  191. int positionHour = value ~/ 60;
  192. int positionMinute = value.remainder(60);
  193. showModalBottomSheet(
  194. context: context,
  195. shape: RoundedRectangleBorder(
  196. borderRadius: BorderRadius.only(
  197. topLeft: Radius.circular(ScreenUtil.getInstance().setSize(16)),
  198. topRight: Radius.circular(ScreenUtil.getInstance().setSize(16)),
  199. )
  200. ),
  201. builder: (context) {
  202. hourScrollCtr.jumpToItem(positionHour);
  203. minuteScrollCtr.jumpToItem(positionMinute);
  204. return Column(
  205. mainAxisSize: MainAxisSize.min,
  206. children: <Widget>[
  207. Container(
  208. height: ScreenUtil.getInstance().setSize(105),
  209. alignment: Alignment.center,
  210. decoration: BoxDecoration(
  211. color: kLingyiWhite,
  212. border: Border(bottom: BorderSide(color: kLingyiGray, width: ScreenUtil.getInstance().setSize(1)))
  213. ),
  214. child: Text('设置提醒', style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(32), color: kLingyiOrange),),
  215. ),
  216. Row(
  217. mainAxisAlignment: MainAxisAlignment.spaceAround,
  218. children: <Widget>[
  219. Expanded(
  220. flex: 1,
  221. child: Container(
  222. height: ScreenUtil.getInstance().setSize(480),
  223. child: CupertinoPicker(
  224. itemExtent: ScreenUtil.getInstance().setSize(80),
  225. onSelectedItemChanged: (index) {
  226. pickHourIndex = index;
  227. },
  228. scrollController: hourScrollCtr,
  229. diameterRatio: 720.0,
  230. // 滚筒的曲率,就是弯曲的程度
  231. useMagnifier: true,
  232. magnification: 1.0,
  233. looping: true,
  234. backgroundColor: kLingyiWhite,
  235. offAxisFraction: 100.0,
  236. // 子项的偏移
  237. children: hourItems.toList(),
  238. )
  239. ),
  240. ),
  241. Expanded(
  242. flex: 1,
  243. child: Container(
  244. height: ScreenUtil.getInstance().setSize(480),
  245. child: CupertinoPicker(
  246. itemExtent: ScreenUtil.getInstance().setSize(80),
  247. onSelectedItemChanged: (index) {
  248. pickMinuteIndex = index;
  249. },
  250. scrollController: minuteScrollCtr,
  251. diameterRatio: 720.0,
  252. // 滚筒的曲率,就是弯曲的程度
  253. useMagnifier: true,
  254. magnification: 1.0,
  255. looping: true,
  256. backgroundColor: kLingyiWhite,
  257. offAxisFraction: 100.0,
  258. // 子项的偏移
  259. children: minuteItems.toList(),
  260. )
  261. ),
  262. )
  263. ],
  264. ),
  265. Container(
  266. height: ScreenUtil.getInstance().setSize(20),
  267. color: kLingyiGray100,
  268. ),
  269. Container(
  270. color: kLingyiWhite,
  271. padding: EdgeInsets.fromLTRB(ScreenUtil.getInstance().setSize(36), 0, ScreenUtil.getInstance().setSize(36), 0),
  272. child: Row(
  273. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  274. children: <Widget>[
  275. Expanded(
  276. flex: 1,
  277. child: GestureDetector(
  278. onTap: () {
  279. Navigator.pop(context);
  280. },
  281. child: Container(
  282. height: ScreenUtil.getInstance().setSize(90),
  283. decoration: BoxDecoration(
  284. border: Border(right: BorderSide(color: kLingyiGray, width: ScreenUtil.getInstance().setSize(1)))
  285. ),
  286. alignment: Alignment.center,
  287. child: Text('取消', style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(32), color: kLingyiText100),),
  288. ),
  289. )
  290. ),
  291. Expanded(
  292. flex: 1,
  293. child: GestureDetector(
  294. onTap: () {
  295. int tempValue = pickHourIndex * 60 + pickMinuteIndex;
  296. for(int i = 0, length = clockList.length; i < length; i++) {
  297. if(clockList[i]['value'] == tempValue) {
  298. showMsg(context, '已设置相同时刻的提醒');
  299. return;
  300. }
  301. }
  302. // 判断是否是编辑
  303. if(editIndex > -1) {
  304. clockList.removeAt(editIndex);
  305. }
  306. Map tempClock = {
  307. 'showValue': hourList[pickHourIndex] + ':' + minuteList[pickMinuteIndex],
  308. 'value': tempValue
  309. };
  310. clockList.add(tempClock);
  311. // 按小到大排序
  312. sortClock();
  313. Navigator.pop(context);
  314. },
  315. child: Container(
  316. height: ScreenUtil.getInstance().setSize(100),
  317. alignment: Alignment.center,
  318. child: Text('确认', style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(32), color: kLingyiGreen),),
  319. ),
  320. )
  321. ),
  322. ],
  323. ),
  324. ),
  325. Container(
  326. color: kLingyiWhite,
  327. height: ScreenUtil.bottomBarHeight,
  328. )
  329. ],
  330. );
  331. },
  332. );
  333. }
  334. void sortClock() {
  335. if (clockList == null || clockList.isEmpty) return;
  336. clockList.sort((b, a) => b['value'].compareTo(a['value']));
  337. setState(() {});
  338. }
  339. @override
  340. Widget build(BuildContext context) {
  341. return Scaffold(
  342. appBar: AppBar(
  343. title: Text(widget.option.query['name']!=null?widget.option.query['name']:'吃药'),
  344. leading: goBackArr(context),
  345. actions: <Widget>[
  346. Container(
  347. padding: EdgeInsets.only(right: 20),
  348. alignment: Alignment.center,
  349. child: MaterialButton(
  350. onPressed: () async {
  351. showToast(context, '保存成功', isSuccess: true, callback: () {
  352. Navigator.pop(context);
  353. });
  354. },
  355. color: kLingyiGreen,
  356. elevation: 0,
  357. minWidth: 50,
  358. height: 24,
  359. child: Text('保存',
  360. style: TextStyle(
  361. fontSize: ScreenUtil.getInstance().setSize(24),
  362. color: kLingyiWhite)),
  363. ),
  364. ),
  365. ],
  366. ),
  367. body: Container(
  368. width: MediaQuery.of(context).size.width,
  369. height: MediaQuery.of(context).size.height,
  370. color: kLingyiGray100,
  371. child: ListView(
  372. children: <Widget>[
  373. Container(
  374. padding: EdgeInsets.only(left: ScreenUtil.getInstance().setSize(36)),
  375. color: kLingyiWhite,
  376. child: Container(
  377. height: ScreenUtil.getInstance().setSize(150),
  378. padding: EdgeInsets.only(right: ScreenUtil.getInstance().setSize(36)),
  379. decoration: BoxDecoration(
  380. border: Border(bottom: BorderSide(color: kLingyiGray, width: ScreenUtil.getInstance().setSize(1)))
  381. ),
  382. child: Row(
  383. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  384. children: <Widget>[
  385. CircleAvatar(
  386. backgroundColor: kLingyiGray400,
  387. radius: ScreenUtil.getInstance().setSize(45),
  388. backgroundImage: getAssetImage(widget.option.query['icon']!=null?widget.option.query['icon']:'2_health/t_drug.png'),
  389. ),
  390. SizedBox(
  391. width: ScreenUtil.getInstance().setSize(520),
  392. child: Text(widget.option.query['name']!=null?widget.option.query['name']:'吃药', style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(32), color: kLingyiText500),),
  393. ),
  394. SizedBox(
  395. width: ScreenUtil.getInstance().setSize(30),
  396. )
  397. // nextPageArr()
  398. ],
  399. ),
  400. )
  401. ),
  402. // 开始时间
  403. GestureDetector(
  404. onTap: () {
  405. showModalBottomSheet(
  406. context: context,
  407. shape: RoundedRectangleBorder(
  408. borderRadius: BorderRadius.only(
  409. topLeft: Radius.circular(ScreenUtil.getInstance().setSize(16)),
  410. topRight: Radius.circular(ScreenUtil.getInstance().setSize(16)),
  411. )
  412. ),
  413. builder: (context) {
  414. startScrollCtr.jumpToItem(pickDateIndex);
  415. return Column(
  416. mainAxisSize: MainAxisSize.min,
  417. children: <Widget>[
  418. Container(
  419. height: ScreenUtil.getInstance().setSize(105),
  420. alignment: Alignment.center,
  421. decoration: BoxDecoration(
  422. color: kLingyiWhite,
  423. border: Border(bottom: BorderSide(color: kLingyiGray, width: ScreenUtil.getInstance().setSize(1)))
  424. ),
  425. child: Text('开始时间', style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(32), color: kLingyiOrange),),
  426. ),
  427. Container(
  428. height: ScreenUtil.getInstance().setSize(480),
  429. child: CupertinoPicker(
  430. itemExtent: ScreenUtil.getInstance().setSize(80),
  431. onSelectedItemChanged: (index) {
  432. pickDateIndex = index;
  433. },
  434. scrollController: startScrollCtr,
  435. diameterRatio: 720.0,
  436. // 滚筒的曲率,就是弯曲的程度
  437. useMagnifier: true,
  438. magnification: 1.0,
  439. looping: true,
  440. backgroundColor: kLingyiWhite,
  441. offAxisFraction: 100.0,
  442. // 子项的偏移
  443. children: startDateItems.toList(),
  444. )
  445. ),
  446. Container(
  447. height: ScreenUtil.getInstance().setSize(20),
  448. color: kLingyiGray100,
  449. ),
  450. Container(
  451. color: kLingyiWhite,
  452. padding: EdgeInsets.fromLTRB(ScreenUtil.getInstance().setSize(36), 0, ScreenUtil.getInstance().setSize(36), 0),
  453. child: Row(
  454. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  455. children: <Widget>[
  456. Expanded(
  457. flex: 1,
  458. child: GestureDetector(
  459. onTap: () {
  460. Navigator.pop(context);
  461. },
  462. child: Container(
  463. height: ScreenUtil.getInstance().setSize(90),
  464. decoration: BoxDecoration(
  465. border: Border(right: BorderSide(color: kLingyiGray, width: ScreenUtil.getInstance().setSize(1)))
  466. ),
  467. alignment: Alignment.center,
  468. child: Text('取消', style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(32), color: kLingyiText100),),
  469. ),
  470. )
  471. ),
  472. Expanded(
  473. flex: 1,
  474. child: GestureDetector(
  475. onTap: () {
  476. setState(() {
  477. startDate = startList[pickDateIndex]['showValue'];
  478. });
  479. createEndDateList(startList[pickDateIndex]['value']);
  480. Navigator.pop(context);
  481. },
  482. child: Container(
  483. height: ScreenUtil.getInstance().setSize(100),
  484. alignment: Alignment.center,
  485. child: Text('确认', style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(32), color: kLingyiGreen),),
  486. ),
  487. )
  488. ),
  489. ],
  490. ),
  491. ),
  492. Container(
  493. color: kLingyiWhite,
  494. height: ScreenUtil.bottomBarHeight,
  495. )
  496. ],
  497. );
  498. },
  499. );
  500. },
  501. child: Container(
  502. padding: EdgeInsets.only(left: ScreenUtil.getInstance().setSize(36)),
  503. color: kLingyiWhite,
  504. child: Container(
  505. height: ScreenUtil.getInstance().setSize(100),
  506. padding: EdgeInsets.only(right: ScreenUtil.getInstance().setSize(36)),
  507. decoration: BoxDecoration(
  508. border: Border(bottom: BorderSide(color: kLingyiGray, width: ScreenUtil.getInstance().setSize(1)))
  509. ),
  510. child: Row(
  511. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  512. children: <Widget>[
  513. SizedBox(
  514. width: ScreenUtil.getInstance().setSize(150),
  515. child: Text('开始时间', style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(28), color: kLingyiText500),),
  516. ),
  517. SizedBox(
  518. width: ScreenUtil.getInstance().setSize(460),
  519. child: Text(startDate, style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(32), color: kLingyiOrange), textAlign: TextAlign.right,),
  520. ),
  521. nextPageArr()
  522. ],
  523. ),
  524. )
  525. ),
  526. ),
  527. // 结束时间
  528. GestureDetector(
  529. onTap: () {
  530. showModalBottomSheet(
  531. context: context,
  532. shape: RoundedRectangleBorder(
  533. borderRadius: BorderRadius.only(
  534. topLeft: Radius.circular(ScreenUtil.getInstance().setSize(16)),
  535. topRight: Radius.circular(ScreenUtil.getInstance().setSize(16)),
  536. )
  537. ),
  538. builder: (context) {
  539. return StatefulBuilder(
  540. builder: (BuildContext context, setState) {
  541. endScrollCtr.jumpToItem(pickEndIndex);
  542. return Column(
  543. mainAxisSize: MainAxisSize.min,
  544. children: <Widget>[
  545. Container(
  546. height: ScreenUtil.getInstance().setSize(105),
  547. alignment: Alignment.center,
  548. decoration: BoxDecoration(
  549. color: kLingyiWhite,
  550. border: Border(bottom: BorderSide(color: kLingyiGray, width: ScreenUtil.getInstance().setSize(1)))
  551. ),
  552. child: Text('结束时间', style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(32), color: kLingyiOrange),),
  553. ),
  554. Container(
  555. width: MediaQuery.of(context).size.height,
  556. height: ScreenUtil.getInstance().setSize(240),
  557. color: kLingyiWhite,
  558. padding: EdgeInsets.fromLTRB(ScreenUtil.getInstance().setSize(36), ScreenUtil.getInstance().setSize(30), ScreenUtil.getInstance().setSize(36), ScreenUtil.getInstance().setSize(30)),
  559. child: GridView.builder(
  560. gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
  561. crossAxisCount: 4,
  562. childAspectRatio: 2,
  563. crossAxisSpacing: 20,
  564. mainAxisSpacing: ScreenUtil.getInstance().setSize(30),
  565. ),
  566. itemCount: durationList.length,
  567. itemBuilder: (BuildContext context, int index) {
  568. return GestureDetector(
  569. onTap: () {
  570. // setPickDurationIndex(index);
  571. setState(() {
  572. pickDurationIndex = index;
  573. });
  574. },
  575. child: Container(
  576. height: ScreenUtil.getInstance().setSize(72),
  577. width: ScreenUtil.getInstance().setSize(145),
  578. decoration: BoxDecoration(
  579. borderRadius: BorderRadius.circular(ScreenUtil.getInstance().setSize(36)),
  580. border: Border.all(color: (pickDurationIndex == index) ? kLingyiGreen : kLingyiGray, width: ScreenUtil.getInstance().setSize(1)),
  581. color: (pickDurationIndex == index) ? kLingyiGreen : kLingyiWhite
  582. ),
  583. child: Stack(
  584. alignment: Alignment.center,
  585. children: <Widget>[
  586. Text(durationList[index], style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(32), color: (pickDurationIndex == index) ? kLingyiWhite : kLingyiText500),)
  587. ],
  588. ),
  589. )
  590. );
  591. }
  592. )
  593. ),
  594. Offstage(
  595. offstage: pickDurationIndex != 6,
  596. child: Container(
  597. height: ScreenUtil.getInstance().setSize(320),
  598. child: CupertinoPicker(
  599. itemExtent: ScreenUtil.getInstance().setSize(80),
  600. onSelectedItemChanged: (index) {
  601. pickEndIndex = index;
  602. },
  603. scrollController: endScrollCtr,
  604. diameterRatio: 720.0,
  605. // 滚筒的曲率,就是弯曲的程度
  606. useMagnifier: true,
  607. magnification: 1.0,
  608. looping: true,
  609. backgroundColor: kLingyiWhite,
  610. offAxisFraction: 100.0,
  611. // 子项的偏移
  612. children: endDateItems.toList(),
  613. )
  614. ),
  615. ),
  616. Container(
  617. height: ScreenUtil.getInstance().setSize(20),
  618. color: kLingyiGray100,
  619. ),
  620. Container(
  621. color: kLingyiWhite,
  622. padding: EdgeInsets.fromLTRB(ScreenUtil.getInstance().setSize(36), 0, ScreenUtil.getInstance().setSize(36), 0),
  623. child: Row(
  624. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  625. children: <Widget>[
  626. Expanded(
  627. flex: 1,
  628. child: GestureDetector(
  629. onTap: () {
  630. Navigator.pop(context);
  631. },
  632. child: Container(
  633. height: ScreenUtil.getInstance().setSize(90),
  634. decoration: BoxDecoration(
  635. border: Border(right: BorderSide(color: kLingyiGray, width: ScreenUtil.getInstance().setSize(1)))
  636. ),
  637. alignment: Alignment.center,
  638. child: Text('取消', style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(32), color: kLingyiText100),),
  639. ),
  640. )
  641. ),
  642. Expanded(
  643. flex: 1,
  644. child: GestureDetector(
  645. onTap: () {
  646. setEndDate();
  647. Navigator.pop(context);
  648. },
  649. child: Container(
  650. height: ScreenUtil.getInstance().setSize(100),
  651. alignment: Alignment.center,
  652. child: Text('确认', style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(32), color: kLingyiGreen),),
  653. ),
  654. )
  655. ),
  656. ],
  657. ),
  658. ),
  659. Container(
  660. color: kLingyiWhite,
  661. height: ScreenUtil.bottomBarHeight,
  662. )
  663. ],
  664. );
  665. },
  666. );
  667. },
  668. );
  669. },
  670. child: Container(
  671. padding: EdgeInsets.only(left: ScreenUtil.getInstance().setSize(36)),
  672. color: kLingyiWhite,
  673. child: Container(
  674. height: ScreenUtil.getInstance().setSize(100),
  675. padding: EdgeInsets.only(right: ScreenUtil.getInstance().setSize(36)),
  676. decoration: BoxDecoration(
  677. border: Border(bottom: BorderSide(color: kLingyiGray, width: ScreenUtil.getInstance().setSize(1)))
  678. ),
  679. child: Row(
  680. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  681. children: <Widget>[
  682. SizedBox(
  683. width: ScreenUtil.getInstance().setSize(150),
  684. child: Text('结束时间', style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(28), color: kLingyiText500),),
  685. ),
  686. SizedBox(
  687. width: ScreenUtil.getInstance().setSize(460),
  688. child: Text(endDate, style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(32), color: kLingyiOrange), textAlign: TextAlign.right,),
  689. ),
  690. nextPageArr()
  691. ],
  692. ),
  693. ),
  694. ),
  695. ),
  696. // 重复
  697. GestureDetector(
  698. onTap: () {
  699. showModalBottomSheet(
  700. context: context,
  701. shape: RoundedRectangleBorder(
  702. borderRadius: BorderRadius.only(
  703. topLeft: Radius.circular(ScreenUtil.getInstance().setSize(16)),
  704. topRight: Radius.circular(ScreenUtil.getInstance().setSize(16)),
  705. )
  706. ),
  707. builder: (context) {
  708. return StatefulBuilder(
  709. builder: (BuildContext context, setState) {
  710. return Column(
  711. mainAxisSize: MainAxisSize.min,
  712. children: <Widget>[
  713. Container(
  714. height: ScreenUtil.getInstance().setSize(105),
  715. alignment: Alignment.center,
  716. decoration: BoxDecoration(
  717. color: kLingyiWhite,
  718. border: Border(bottom: BorderSide(color: kLingyiGray, width: ScreenUtil.getInstance().setSize(1)))
  719. ),
  720. child: Text('任务频率', style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(32), color: kLingyiOrange),),
  721. ),
  722. Container(
  723. width: MediaQuery.of(context).size.height,
  724. height: ScreenUtil.getInstance().setSize(240),
  725. color: kLingyiWhite,
  726. padding: EdgeInsets.fromLTRB(ScreenUtil.getInstance().setSize(36), ScreenUtil.getInstance().setSize(30), ScreenUtil.getInstance().setSize(36), ScreenUtil.getInstance().setSize(30)),
  727. child: GridView.builder(
  728. gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
  729. crossAxisCount: 4,
  730. childAspectRatio: 2,
  731. crossAxisSpacing: 20,
  732. mainAxisSpacing: ScreenUtil.getInstance().setSize(30),
  733. ),
  734. itemCount: weekList.length,
  735. itemBuilder: (BuildContext context, int index) {
  736. return GestureDetector(
  737. onTap: () {
  738. weekList[index]['isPick'] = !weekList[index]['isPick'];
  739. if(index == weekList.length-1) {
  740. // 全选与反选
  741. for(int i = 0, length = weekList.length-1; i < length; i++) {
  742. weekList[i]['isPick'] = weekList[index]['isPick'];
  743. }
  744. }else {
  745. // 判断是否全选
  746. if(weekList[index]['isPick']) {
  747. weekList.last['isPick'] = true;
  748. for(int i = 0, length = weekList.length-1; i < length; i++) {
  749. if(!weekList[i]['isPick']) {
  750. weekList.last['isPick'] = false;
  751. break;
  752. }
  753. }
  754. }else {
  755. weekList.last['isPick'] = false;
  756. }
  757. }
  758. setState(() {});
  759. },
  760. child: Container(
  761. height: ScreenUtil.getInstance().setSize(72),
  762. padding: EdgeInsets.fromLTRB(ScreenUtil.getInstance().setSize(36), 0, ScreenUtil.getInstance().setSize(36), 0),
  763. decoration: BoxDecoration(
  764. borderRadius: BorderRadius.circular(ScreenUtil.getInstance().setSize(36)),
  765. border: Border.all(color: weekList[index]['isPick'] ? kLingyiGreen : kLingyiGray, width: ScreenUtil.getInstance().setSize(1)),
  766. color: weekList[index]['isPick'] ? kLingyiGreen : kLingyiWhite
  767. ),
  768. child: Stack(
  769. alignment: Alignment.center,
  770. children: <Widget>[
  771. Text(weekList[index]['showValue'], style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(32), color: weekList[index]['isPick'] ? kLingyiWhite : kLingyiText500),)
  772. ],
  773. ),
  774. )
  775. );
  776. }
  777. )
  778. ),
  779. Container(
  780. height: ScreenUtil.getInstance().setSize(100),
  781. color: kLingyiGray100,
  782. alignment: Alignment.center,
  783. child: RichText(
  784. text: TextSpan(
  785. children: [
  786. TextSpan(
  787. text: '由',
  788. style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(32), color: kLingyiText100),
  789. ),
  790. TextSpan(
  791. text: startDate,
  792. style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(32), color: kLingyiOrange),
  793. ),
  794. TextSpan(
  795. text: '开始,每天坚持',
  796. style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(32), color: kLingyiText100),
  797. ),
  798. ]
  799. ),
  800. ),
  801. ),
  802. Container(
  803. color: kLingyiWhite,
  804. padding: EdgeInsets.fromLTRB(ScreenUtil.getInstance().setSize(36), 0, ScreenUtil.getInstance().setSize(36), 0),
  805. child: Row(
  806. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  807. children: <Widget>[
  808. Expanded(
  809. flex: 1,
  810. child: GestureDetector(
  811. onTap: () {
  812. Navigator.pop(context);
  813. },
  814. child: Container(
  815. height: ScreenUtil.getInstance().setSize(90),
  816. decoration: BoxDecoration(
  817. border: Border(right: BorderSide(color: kLingyiGray, width: ScreenUtil.getInstance().setSize(1)))
  818. ),
  819. alignment: Alignment.center,
  820. child: Text('取消', style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(32), color: kLingyiText100),),
  821. ),
  822. )
  823. ),
  824. Expanded(
  825. flex: 1,
  826. child: GestureDetector(
  827. onTap: () {
  828. setCurrentWeek();
  829. Navigator.pop(context);
  830. },
  831. child: Container(
  832. height: ScreenUtil.getInstance().setSize(100),
  833. alignment: Alignment.center,
  834. child: Text('确认', style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(32), color: kLingyiGreen),),
  835. ),
  836. )
  837. ),
  838. ],
  839. ),
  840. ),
  841. Container(
  842. color: kLingyiWhite,
  843. height: ScreenUtil.bottomBarHeight,
  844. )
  845. ],
  846. );
  847. }
  848. );
  849. },
  850. );
  851. },
  852. child: Container(
  853. padding: EdgeInsets.only(left: ScreenUtil.getInstance().setSize(36)),
  854. color: kLingyiWhite,
  855. child: Container(
  856. height: ScreenUtil.getInstance().setSize(100),
  857. padding: EdgeInsets.only(right: ScreenUtil.getInstance().setSize(36)),
  858. decoration: BoxDecoration(
  859. border: Border(bottom: BorderSide(color: kLingyiGray, width: ScreenUtil.getInstance().setSize(1)))
  860. ),
  861. child: Row(
  862. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  863. children: <Widget>[
  864. SizedBox(
  865. width: ScreenUtil.getInstance().setSize(150),
  866. child: Text('重复', style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(28), color: kLingyiText500),),
  867. ),
  868. SizedBox(
  869. width: ScreenUtil.getInstance().setSize(460),
  870. child: Text(currentWeek, style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(32), color: kLingyiText500), textAlign: TextAlign.right,),
  871. ),
  872. nextPageArr()
  873. ],
  874. ),
  875. ),
  876. ),
  877. ),
  878. // 提醒
  879. Container(
  880. padding: EdgeInsets.only(left: ScreenUtil.getInstance().setSize(36)),
  881. color: kLingyiWhite,
  882. child: Container(
  883. height: ScreenUtil.getInstance().setSize(100),
  884. padding: EdgeInsets.only(right: ScreenUtil.getInstance().setSize(36)),
  885. child: Row(
  886. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  887. children: <Widget>[
  888. SizedBox(
  889. width: ScreenUtil.getInstance().setSize(150),
  890. child: Text('提醒', style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(28), color: kLingyiText500),),
  891. ),
  892. CupertinoSwitch(
  893. value: isWork,
  894. onChanged: (value) async {
  895. setState(() {
  896. isWork = value;
  897. });
  898. }
  899. ),
  900. ],
  901. ),
  902. ),
  903. ),
  904. Container(
  905. padding: EdgeInsets.only(left: ScreenUtil.getInstance().setSize(36)),
  906. color: kLingyiWhite,
  907. child: Container(
  908. height: ScreenUtil.getInstance().setSize(clockList.length < 5 ? 120 : 240),
  909. padding: EdgeInsets.only(right: ScreenUtil.getInstance().setSize(12)),
  910. decoration: BoxDecoration(
  911. border: Border(bottom: BorderSide(color: kLingyiGray, width: ScreenUtil.getInstance().setSize(1)))
  912. ),
  913. child: GridView.builder(
  914. padding: EdgeInsets.only(right: ScreenUtil.getInstance().setSize(24)),
  915. gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
  916. crossAxisCount: 5,
  917. childAspectRatio: 2,
  918. crossAxisSpacing: 10,
  919. mainAxisSpacing: ScreenUtil.getInstance().setSize(30),
  920. ),
  921. itemCount: clockList.length+1,
  922. itemBuilder: (BuildContext context, int index) {
  923. if(index < clockList.length) {
  924. return GestureDetector(
  925. onTap: () {
  926. showClockPick(clockList[index]['value'], editIndex: index);
  927. },
  928. child: Container(
  929. padding: EdgeInsets.only(top: ScreenUtil.getInstance().setSize(12)),
  930. width: ScreenUtil.getInstance().setSize(120),
  931. child: Stack(
  932. overflow: Overflow.visible,
  933. children: <Widget>[
  934. Positioned(
  935. left: 0,
  936. top: 0,
  937. width: ScreenUtil.getInstance().setSize(120),
  938. height: ScreenUtil.getInstance().setSize(76),
  939. child: Container(
  940. width: ScreenUtil.getInstance().setSize(120),
  941. height: ScreenUtil.getInstance().setSize(76),
  942. decoration: BoxDecoration(
  943. color: Color(0xfff5f5f5),
  944. borderRadius: BorderRadius.circular(ScreenUtil.getInstance().setSize(8))
  945. ),
  946. child: Stack(
  947. alignment: Alignment.center,
  948. children: <Widget>[
  949. Text(clockList[index]['showValue'], style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(32), color: kLingyiText500),)
  950. ],
  951. ),
  952. ),
  953. ),
  954. Positioned(
  955. right: ScreenUtil.getInstance().setSize(-12),
  956. top: ScreenUtil.getInstance().setSize(-12),
  957. width: ScreenUtil.getInstance().setSize(36),
  958. height: ScreenUtil.getInstance().setSize(36),
  959. child: GestureDetector(
  960. onTap: () {
  961. // 删除对应闹钟
  962. clockList.removeAt(index);
  963. setState(() {});
  964. },
  965. child: CircleAvatar(
  966. radius: ScreenUtil.getInstance().setSize(36),
  967. backgroundColor: kLingyiGray300,
  968. backgroundImage: getAssetImage('2_health/s_delete.png'),
  969. )
  970. ),
  971. )
  972. ],
  973. ),
  974. )
  975. );
  976. }else {
  977. return Offstage(
  978. offstage: clockList.length > 9,
  979. child: GestureDetector(
  980. onTap: () {
  981. showClockPick(0);
  982. },
  983. child: Container(
  984. padding: EdgeInsets.only(top: ScreenUtil.getInstance().setSize(12)),
  985. width: ScreenUtil.getInstance().setSize(120),
  986. child: Stack(
  987. overflow: Overflow.visible,
  988. children: <Widget>[
  989. Positioned(
  990. left: 0,
  991. top: 0,
  992. width: ScreenUtil.getInstance().setSize(120),
  993. height: ScreenUtil.getInstance().setSize(76),
  994. child: Container(
  995. width: ScreenUtil.getInstance().setSize(120),
  996. height: ScreenUtil.getInstance().setSize(76),
  997. decoration: BoxDecoration(
  998. color: Color(0xfff5f5f5),
  999. borderRadius: BorderRadius.circular(ScreenUtil.getInstance().setSize(8))
  1000. ),
  1001. child: Stack(
  1002. alignment: Alignment.center,
  1003. children: <Widget>[
  1004. Image(
  1005. width: ScreenUtil.getInstance().setSize(32),
  1006. height: ScreenUtil.getInstance().setSize(32),
  1007. fit: BoxFit.cover,
  1008. image: getAssetImage('2_health/i_add.png'),
  1009. )
  1010. ],
  1011. ),
  1012. ),
  1013. ),
  1014. ],
  1015. ),
  1016. )
  1017. )
  1018. );
  1019. }
  1020. }
  1021. )
  1022. ),
  1023. ),
  1024. // 提醒音
  1025. GestureDetector(
  1026. onTap: () async{
  1027. var res = await Navigator.of(context).push(
  1028. MaterialPageRoute(builder: (BuildContext context) {
  1029. return AppRoute.getPage('page://health/ringing', {});
  1030. })
  1031. );
  1032. if (res != null) {
  1033. print(res['info']);
  1034. setState(() {
  1035. ringing = res['info'];
  1036. });
  1037. }
  1038. },
  1039. child: Container(
  1040. padding: EdgeInsets.only(left: ScreenUtil.getInstance().setSize(36)),
  1041. color: kLingyiWhite,
  1042. child: Container(
  1043. height: ScreenUtil.getInstance().setSize(100),
  1044. padding: EdgeInsets.only(right: ScreenUtil.getInstance().setSize(36)),
  1045. decoration: BoxDecoration(
  1046. border: Border(bottom: BorderSide(color: kLingyiGray, width: ScreenUtil.getInstance().setSize(1)))
  1047. ),
  1048. child: Row(
  1049. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  1050. children: <Widget>[
  1051. SizedBox(
  1052. width: ScreenUtil.getInstance().setSize(150),
  1053. child: Text('提醒音', style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(28), color: kLingyiText500),),
  1054. ),
  1055. SizedBox(
  1056. width: ScreenUtil.getInstance().setSize(460),
  1057. child: Text(ringing, style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(32), color: kLingyiText500), textAlign: TextAlign.right,),
  1058. ),
  1059. nextPageArr()
  1060. ],
  1061. ),
  1062. ),
  1063. ),
  1064. )
  1065. // 更多提醒方式
  1066. // Container(
  1067. // padding: EdgeInsets.only(left: ScreenUtil.getInstance().setSize(36)),
  1068. // color: kLingyiWhite,
  1069. // child: Container(
  1070. // height: ScreenUtil.getInstance().setSize(100),
  1071. // padding: EdgeInsets.only(right: ScreenUtil.getInstance().setSize(36)),
  1072. // decoration: BoxDecoration(
  1073. // border: Border(bottom: BorderSide(color: kLingyiGray, width: ScreenUtil.getInstance().setSize(1)))
  1074. // ),
  1075. // child: Row(
  1076. // mainAxisAlignment: MainAxisAlignment.spaceBetween,
  1077. // children: <Widget>[
  1078. // SizedBox(
  1079. // width: ScreenUtil.getInstance().setSize(200),
  1080. // child: Text('更多提醒方式', style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(28), color: kLingyiText500),),
  1081. // ),
  1082. // SizedBox(
  1083. // width: ScreenUtil.getInstance().setSize(410),
  1084. // child: Row(
  1085. // mainAxisAlignment: MainAxisAlignment.end,
  1086. // children: <Widget>[
  1087. // ClipRRect(
  1088. // borderRadius: BorderRadius.circular(ScreenUtil.getInstance().setSize(8)),
  1089. // child: Image(
  1090. // width: ScreenUtil.getInstance().setSize(48),
  1091. // height: ScreenUtil.getInstance().setSize(48),
  1092. // image: getAssetImage('default.png'),
  1093. // fit: BoxFit.cover,
  1094. // ),
  1095. // ),
  1096. // SizedBox(width: ScreenUtil.getInstance().setSize(24),),
  1097. // ClipRRect(
  1098. // borderRadius: BorderRadius.circular(ScreenUtil.getInstance().setSize(8)),
  1099. // child: Image(
  1100. // width: ScreenUtil.getInstance().setSize(48),
  1101. // height: ScreenUtil.getInstance().setSize(48),
  1102. // image: getAssetImage('default.png'),
  1103. // fit: BoxFit.cover,
  1104. // ),
  1105. // ),
  1106. // SizedBox(width: ScreenUtil.getInstance().setSize(24),),
  1107. // ClipRRect(
  1108. // borderRadius: BorderRadius.circular(ScreenUtil.getInstance().setSize(8)),
  1109. // child: Image(
  1110. // width: ScreenUtil.getInstance().setSize(48),
  1111. // height: ScreenUtil.getInstance().setSize(48),
  1112. // image: getAssetImage('default.png'),
  1113. // fit: BoxFit.cover,
  1114. // ),
  1115. // ),
  1116. // ],
  1117. // ),
  1118. // ),
  1119. // nextPageArr()
  1120. // ],
  1121. // ),
  1122. // ),
  1123. // )
  1124. ],
  1125. )
  1126. )
  1127. );
  1128. }
  1129. }

封装空列表呈现组件

  1. import 'package:flutter/material.dart';
  2. import 'package:lingyi/config/color.dart';
  3. import 'package:lingyi/util/common.dart';
  4. class Nothing extends StatelessWidget {
  5. final String title;
  6. final double height;
  7. final Color bgColor;
  8. final bool isLoading;
  9. Nothing(this.title, {this.height, this.bgColor, this.isLoading=false});
  10. @override
  11. Widget build(BuildContext context) {
  12. return Container(
  13. padding: EdgeInsets.only(bottom: ScreenUtil.getInstance().setSize(100)),
  14. width: MediaQuery.of(context).size.width,
  15. height: height ?? MediaQuery.of(context).size.height,
  16. decoration: BoxDecoration(
  17. color: bgColor ?? kLingyiGray100
  18. ),
  19. alignment: Alignment.center,
  20. child: Column(
  21. mainAxisAlignment: MainAxisAlignment.center,
  22. crossAxisAlignment: CrossAxisAlignment.center,
  23. children: <Widget>[
  24. isLoading ? Image(image: getAssetImage('1_circle/loading.png'), width: ScreenUtil.getInstance().setSize(380), fit: BoxFit.fitWidth,)
  25. : Image(image: getAssetImage('5_public/default.png'), width: ScreenUtil.getInstance().setSize(420), fit: BoxFit.fitWidth,),
  26. SizedBox(width: ScreenUtil.getInstance().setSize(30)),
  27. Offstage(
  28. offstage: isLoading,
  29. child: Text(title, style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(28), color: kLingyiText100),)
  30. )
  31. ],
  32. ),
  33. );
  34. }
  35. }

安全区域的使用

  1. 1. 弹窗使用ScreenUtil.bottomBarHeight在底部增加高度
  2. 2. 使用SafeArea组件包括整个应用

根页面返回键退出App处理

  1. 使用 WillPopScope 组件包括入口组件
  2. Future<bool> _onWillPop() async {
  3. ShowAlert.show(context, '确定退出应用吗?', onConfirm: () {
  4. SystemNavigator.pop();
  5. });
  6. return false;
  7. }

webView 页面友好处理

  1. import 'package:flutter/material.dart';
  2. import 'package:webview_flutter/webview_flutter.dart';
  3. import 'package:annotation_route/route.dart';
  4. import 'package:lingyi/config/color.dart';
  5. @ARoute(url: 'page://webview')
  6. class Webview extends StatefulWidget {
  7. final dynamic option;
  8. Webview(this.option);
  9. @override
  10. WebviewState createState() => WebviewState();
  11. }
  12. class WebviewState extends State<Webview> {
  13. bool isLoading = true;
  14. @override
  15. Widget build(BuildContext context) {
  16. String url = widget.option.query['url'];
  17. String title = widget.option.query['title'];
  18. return Scaffold(
  19. appBar: AppBar(
  20. title: Text(title),
  21. leading: goBackArr(context),
  22. bottom: PreferredSize(
  23. preferredSize: Size.fromHeight(ScreenUtil.getInstance().setSize(4)),
  24. child: Offstage(
  25. offstage: !isLoading,
  26. child: SizedBox(
  27. height: ScreenUtil.getInstance().setSize(4),
  28. width: MediaQuery.of(context).size.width,
  29. child: LinearProgressIndicator(),
  30. ),
  31. ),
  32. ),
  33. ),
  34. body: WebView(
  35. onWebViewCreated: (WebViewController web) {
  36. setState(() {
  37. isLoading = true;
  38. });
  39. },
  40. onPageFinished: (String value) {
  41. setState(() {
  42. isLoading = false;
  43. });
  44. },
  45. initialUrl: url,
  46. javascriptMode: JavascriptMode.unrestricted,
  47. ),
  48. );
  49. }
  50. }

pdf 预览功能

  1. import 'dart:async';
  2. import 'dart:io';
  3. import 'package:flutter/foundation.dart';
  4. import 'package:flutter/material.dart';
  5. import 'package:flutter_full_pdf_viewer/full_pdf_viewer_scaffold.dart';
  6. import 'package:path_provider/path_provider.dart';
  7. import 'package:annotation_route/route.dart';
  8. import 'package:lingyi/config/color.dart';
  9. import 'package:lingyi/util/common.dart';
  10. // import 'package:flutter/services.dart' show rootBundle;
  11. // import 'dart:typed_data';
  12. @ARoute(url: 'page://pdfview')
  13. class Pdfview extends StatefulWidget {
  14. final dynamic option;
  15. Pdfview(this.option);
  16. @override
  17. PdfviewState createState() => new PdfviewState();
  18. }
  19. class PdfviewState extends State<Pdfview> {
  20. String pathPDF = "";
  21. @override
  22. void initState() {
  23. super.initState();
  24. createFileOfPdfUrl().then((f) {
  25. print(f.toString());
  26. setState(() {
  27. pathPDF = f.path;
  28. print(pathPDF);
  29. });
  30. });
  31. }
  32. Future<File> createFileOfPdfUrl() async {
  33. final url = "http://africau.edu/images/default/sample.pdf";
  34. final filename = url.substring(url.lastIndexOf("/") + 1);
  35. var request = await HttpClient().getUrl(Uri.parse(url));
  36. var response = await request.close();
  37. var bytes = await consolidateHttpClientResponseBytes(response);
  38. String dir = (await getApplicationDocumentsDirectory()).path;
  39. File file = new File('$dir/$filename');
  40. await file.writeAsBytes(bytes);
  41. return file;
  42. }
  43. // @override
  44. // void initState() {
  45. // super.initState();
  46. // print('init');
  47. // printFile();
  48. // createFileOfPdfUrl().then((f) {
  49. // setState(() {
  50. // pathPDF = f.path;
  51. // print(pathPDF);
  52. // });
  53. // });
  54. // }
  55. // void printFile() async {
  56. // var filebd = await rootBundle.load("assets/data/cannon.pdf");
  57. // print(filebd.runtimeType);
  58. // }
  59. // Future<void> writeToFile(ByteData data, String path) {
  60. // final buffer = data.buffer;
  61. // return new File(path).writeAsBytes(
  62. // buffer.asUint8List(data.offsetInBytes, data.lengthInBytes));
  63. // }
  64. // Future<File> createFileOfPdfUrl() async {
  65. // final filename = 'test.pdf';
  66. // var bytes = await rootBundle.load("assets/data/cannon.pdf");
  67. // String dir = (await getApplicationDocumentsDirectory()).path;
  68. // writeToFile(bytes,'$dir/$filename');
  69. // File file = new File('$dir/$filename');
  70. // return file;
  71. // }
  72. @override
  73. Widget build(BuildContext context) {
  74. return pathPDF.isEmpty ? Scaffold(
  75. appBar: AppBar(
  76. title: Text("Document"),
  77. ),
  78. body: Container(
  79. padding: EdgeInsets.only(bottom: ScreenUtil.getInstance().setSize(100)),
  80. width: MediaQuery.of(context).size.width,
  81. height: MediaQuery.of(context).size.height,
  82. decoration: BoxDecoration(
  83. color: kLingyiGray100
  84. ),
  85. alignment: Alignment.center,
  86. child: Column(
  87. mainAxisAlignment: MainAxisAlignment.center,
  88. crossAxisAlignment: CrossAxisAlignment.center,
  89. children: <Widget>[
  90. Image(image: getAssetImage('5_public/default.png'), width: ScreenUtil.getInstance().setSize(420), fit: BoxFit.fitWidth,),
  91. SizedBox(width: ScreenUtil.getInstance().setSize(30)),
  92. Text('加载中...', style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(28), color: kLingyiText100),)
  93. ],
  94. ),
  95. )
  96. ) : PDFViewerScaffold(
  97. appBar: AppBar(
  98. title: Text("Document"),
  99. ),
  100. path: pathPDF
  101. );
  102. }
  103. }