goto_page.dart 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. /*
  2. *
  3. * 路由封装
  4. * @params* [context] 当前页面上下文
  5. * @params* [targetPage] 跳转页面 非命名参数跳转时是 BuildContext 类型,路由命名参数跳转时是 字符串类型
  6. * @params [isPushNamed] 是否是命名参数跳转 默认false 非命名参数跳转; true 是
  7. * @params [arguments] 携带的参数 默认null
  8. * @params [opaque] 是否背景透明 默认false 不透明; true为透明
  9. * @params [isReplace] 是否替换当前页面 A-B 默认0 不替换; // 0 不替换 1 替换当前 2 替换当前及之前所有
  10. * @params [cb] // 返回上一级的回调函数 value 为传给上一级的参数
  11. *
  12. *
  13. *
  14. * 用法:
  15. * // 页面跳转
  16. GotoPage.pushPage(
  17. context: context,
  18. // targetPage: AppRoutes.mePage,
  19. targetPage: MePage(),
  20. animationType: AnimationType.rightToLeft,
  21. arguments: {"name": "gaolong"},
  22. cb: (value) => {print("---mePage返回的数据---$value------")},
  23. );
  24. *
  25. *
  26. *
  27. */
  28. import 'package:flutter/cupertino.dart';
  29. import 'package:flutter/material.dart';
  30. import 'device_utils.dart';
  31. //页面跳转动画的方式
  32. enum AnimationType { rightToLeft, leftToRight, bottomToTop, topToBottom }
  33. class GotoPage {
  34. // 非命名方式跳转 直接初始化页面对象
  35. static void _switchPageNotNamed({
  36. required BuildContext context,
  37. required dynamic targetPage,
  38. AnimationType? animationType = AnimationType.rightToLeft,
  39. int startMills = 300, // 动画过渡时间 300ms
  40. Object? arguments,
  41. num isReplace = 0, // 0 不替换 1 替换当前 2 替换当前及之前所有
  42. void Function(dynamic value)? cb,
  43. }) {
  44. PageRoute pageRoute;
  45. if (DeviceUtils.isAndroid) {
  46. // 安卓
  47. pageRoute = PageRouteBuilder(
  48. settings: RouteSettings(name: context.widget.key.toString(), arguments: arguments),
  49. transitionDuration: Duration(milliseconds: startMills),
  50. transitionsBuilder: (BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget child) {
  51. return SlideTransition(
  52. position: _createSlideTween(animationType).animate(animation),
  53. child: child,
  54. );
  55. },
  56. pageBuilder: (BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) {
  57. return targetPage;
  58. },
  59. );
  60. } else if (DeviceUtils.isIOS) {
  61. // 苹果
  62. pageRoute = CupertinoPageRoute(
  63. builder: (BuildContext context) {
  64. return targetPage;
  65. },
  66. settings: RouteSettings(name: context.widget.key.toString(), arguments: arguments),
  67. );
  68. } else {
  69. // 其他
  70. pageRoute = MaterialPageRoute(
  71. builder: (BuildContext context) {
  72. return targetPage;
  73. },
  74. settings: RouteSettings(name: context.widget.key.toString(), arguments: arguments),
  75. );
  76. }
  77. if (isReplace == 0) {
  78. // 不替换
  79. Navigator.of(context).push(pageRoute).then((value) {
  80. if (cb != null) {
  81. cb(value);
  82. }
  83. });
  84. } else if (isReplace == 1) {
  85. // 替换当前
  86. Navigator.of(context).pushReplacement(pageRoute).then((value) {
  87. if (cb != null) {
  88. cb(value);
  89. }
  90. });
  91. } else {
  92. // 替换当前及之前所有
  93. Navigator.of(context).pushAndRemoveUntil(pageRoute, (Route<dynamic>? route) => route == null).then((value) {
  94. if (cb != null) {
  95. cb(value);
  96. }
  97. });
  98. }
  99. }
  100. // 命名路由方式跳转
  101. static void _switchPageByNamed({
  102. required BuildContext context,
  103. required String targetPage,
  104. AnimationType? animationType = AnimationType.rightToLeft,
  105. int startMills = 300, // 动画过渡时间 300ms
  106. Object? arguments,
  107. num isReplace = 0, // 0 不替换 1 替换当前 2 替换当前及之前所有
  108. void Function(dynamic value)? cb, // 返回上一级的回调函数 value 为传给上一级的参数
  109. }) {
  110. if (isReplace == 0) {
  111. // 不替换
  112. Navigator.of(context).pushNamed(targetPage, arguments: arguments).then((value) => {
  113. if (cb != null) {cb(value)}
  114. });
  115. } else if (isReplace == 1) {
  116. // 替换当前
  117. Navigator.of(context).pushReplacementNamed(targetPage, arguments: arguments).then((value) => {
  118. if (cb != null) {cb(value)}
  119. });
  120. } else {
  121. // 替换当前及以前所有
  122. Navigator.of(context)
  123. .pushNamedAndRemoveUntil(targetPage, (Route route) => false, arguments: arguments)
  124. .then((value) => {
  125. if (cb != null) {cb(value)}
  126. });
  127. }
  128. }
  129. /// 1、普通跳转
  130. static void pushPage({
  131. required BuildContext context,
  132. required dynamic targetPage, // 非命名跳转时类型是 PageRoute 命令跳转时是 String
  133. AnimationType? animationType = AnimationType.rightToLeft,
  134. int startMills = 300, // 动画过渡时间 300ms
  135. Object? arguments, //携带参数
  136. num isReplace = 0, // 0 不替换 1 替换当前 2 替换当前及之前所有
  137. void Function(dynamic value)? cb, // 返回上一级的回调函数 value 为传给上一级的参数
  138. }) {
  139. bool _isPushNamed = targetPage is String ? true : false;
  140. if (!_isPushNamed) {
  141. //非路由命名方式跳转
  142. _switchPageNotNamed(
  143. context: context,
  144. targetPage: targetPage,
  145. animationType: animationType,
  146. startMills: startMills,
  147. arguments: arguments,
  148. isReplace: isReplace,
  149. cb: cb,
  150. );
  151. } else {
  152. // 路由命名跳转
  153. _switchPageByNamed(
  154. context: context,
  155. targetPage: targetPage,
  156. animationType: animationType,
  157. startMills: startMills,
  158. arguments: arguments,
  159. isReplace: isReplace,
  160. cb: cb,
  161. );
  162. }
  163. }
  164. /// 2、滑动过渡跳转
  165. static void pushPageBySlide({
  166. required BuildContext context,
  167. required dynamic targetPage, // 非命名跳转时类型是 PageRoute 命令跳转时是 String
  168. //默认'rightToLeft', 'leftToRight' 'bottomToTop' 'topToBottom'
  169. AnimationType? animationType = AnimationType.rightToLeft,
  170. bool? isPushNamed = true, // 是否是路由命名跳转 true 是 false 否
  171. bool opaque = true, // 背景透明方式 true: 不透明 false: 透明
  172. Object? arguments,
  173. int startMills = 300,
  174. num isReplace = 0, // 0 不替换 1 替换当前 2 替换当前及之前所有
  175. void Function(dynamic value)? cb, // 返回上一级的回调函数 value 为传给上一级的参数
  176. }) {
  177. bool _isPushNamed = targetPage is String ? true : false;
  178. if (_isPushNamed) {
  179. // 命名跳转 命名跳转时 没有动画效果 默认页面从 右向左切换
  180. _switchPageByNamed(
  181. context: context, targetPage: targetPage, arguments: arguments, isReplace: isReplace, cb: cb);
  182. } else {
  183. // 非命名跳转
  184. PageRoute pageRoute = PageRouteBuilder(
  185. settings: RouteSettings(name: context.widget.key.toString(), arguments: arguments),
  186. ///背景透明方式 true: 不透明 false: 透明
  187. opaque: opaque,
  188. pageBuilder: (BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) {
  189. return targetPage;
  190. },
  191. transitionDuration: Duration(milliseconds: startMills),
  192. ///动画
  193. transitionsBuilder:
  194. (BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget child) {
  195. return SlideTransition(
  196. position: _createSlideTween(animationType).animate(animation),
  197. child: child,
  198. );
  199. },
  200. );
  201. if (isReplace == 0) {
  202. /// 不替换
  203. Navigator.of(context).push(pageRoute).then((value) {
  204. if (cb != null) {
  205. cb(value);
  206. }
  207. });
  208. } else if (isReplace == 1) {
  209. /// 替换当前
  210. Navigator.of(context).pushReplacement(pageRoute).then((value) {
  211. if (cb != null) {
  212. cb(value);
  213. }
  214. });
  215. } else {
  216. /// 替换当前及之前所有
  217. Navigator.of(context).pushAndRemoveUntil(pageRoute, (Route<dynamic>? route) => route == null).then((value) {
  218. if (cb != null) {
  219. cb(value);
  220. }
  221. });
  222. }
  223. }
  224. }
  225. static _createSlideTween(animationType) {
  226. Offset currentOffset;
  227. switch (animationType) {
  228. case AnimationType.rightToLeft:
  229. currentOffset = Offset(1, 0);
  230. break;
  231. case AnimationType.leftToRight:
  232. currentOffset = Offset(-1, 0);
  233. break;
  234. case AnimationType.bottomToTop:
  235. currentOffset = Offset(0, 1);
  236. break;
  237. case AnimationType.topToBottom:
  238. currentOffset = Offset(0, -1);
  239. break;
  240. default:
  241. currentOffset = Offset(1, 0);
  242. }
  243. return Tween<Offset>(
  244. begin: currentOffset,
  245. end: Offset.zero,
  246. );
  247. }
  248. /// 3、带渐变动画跳转
  249. static void pushPageByFade({
  250. required BuildContext context,
  251. required Widget targetPage,
  252. bool opaque = false, // 背景透明方式 true: 不透明 false: 透明
  253. dynamic arguments,
  254. int startMills = 300,
  255. num isReplace = 0, // 0 不替换 1 替换当前 2 替换当前及之前所有
  256. Function(dynamic value)? cb, // 返回上一级的回调函数 value 为传给上一级的参数
  257. }) {
  258. PageRoute pageRoute = PageRouteBuilder(
  259. settings: RouteSettings(name: context.widget.key.toString(), arguments: arguments ?? null),
  260. ///背景透明方式 true: 不透明 false: 透明
  261. opaque: opaque,
  262. pageBuilder: (BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) {
  263. return targetPage;
  264. },
  265. transitionDuration: Duration(milliseconds: startMills),
  266. ///动画
  267. transitionsBuilder:
  268. (BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget child) {
  269. return FadeTransition(
  270. opacity: animation,
  271. child: child,
  272. );
  273. },
  274. );
  275. if (isReplace == 0) {
  276. /// 不替换
  277. Navigator.of(context).push(pageRoute).then((value) {
  278. if (cb != null) {
  279. cb(value);
  280. }
  281. });
  282. } else if (isReplace == 1) {
  283. /// 替换当前
  284. Navigator.of(context).pushReplacement(pageRoute).then((value) {
  285. if (cb != null) {
  286. cb(value);
  287. }
  288. });
  289. } else {
  290. /// 替换当前及之前所有
  291. Navigator.of(context).pushAndRemoveUntil(pageRoute, (Route<dynamic>? route) => route == null).then((value) {
  292. if (cb != null) {
  293. cb(value);
  294. }
  295. });
  296. }
  297. }
  298. static Route _createRoute(parentContext, Widget targetPage, int startMills, int reversMills, bool opaque, {dynamic arguments}) {
  299. return PageRouteBuilder<void>(
  300. settings: RouteSettings(name: parentContext?.widget?.key ?? '', arguments: arguments ?? null),
  301. opaque: opaque,
  302. // 背景透明方式 true: 不透明 false: 透明
  303. pageBuilder: (context, animation, secondaryAnimation) {
  304. return targetPage;
  305. },
  306. transitionDuration: Duration(milliseconds: startMills),
  307. reverseTransitionDuration: Duration(milliseconds: reversMills),
  308. transitionsBuilder: (context, animation, secondaryAnimation, child) {
  309. var rectAnimation = _createTween(parentContext).chain(CurveTween(curve: Curves.ease)).animate(animation);
  310. return Stack(
  311. children: [
  312. PositionedTransition(rect: rectAnimation, child: child),
  313. ],
  314. );
  315. },
  316. );
  317. }
  318. static Tween<RelativeRect> _createTween(BuildContext context) {
  319. var windowSize = MediaQuery.of(context).size;
  320. var box = context.findRenderObject() as RenderBox;
  321. var rect = box.localToGlobal(Offset.zero) & box.size;
  322. var relativeRect = RelativeRect.fromSize(rect, windowSize);
  323. return RelativeRectTween(
  324. begin: relativeRect,
  325. end: RelativeRect.fill,
  326. );
  327. }
  328. }