Flutter利用注解生成可自定義的路由的實(shí)現(xiàn)
route_generator是什么
這是一個(gè)簡(jiǎn)單的 Flutter 路由生成庫(kù),只需要少量的代碼,然后利用注解配合源代碼生成,自動(dòng)生成路由表,省去手工管理路由代碼的煩惱。
特性
- 自定義路由名稱(chēng)
- 自定義路由動(dòng)畫(huà)
- 自定義路由參數(shù)
- 自定義路由邏輯
依賴(lài)
dependencies: # Your other regular dependencies here route_annotation: ^0.1.0 dev_dependencies: # Your other dev_dependencies here build_runner: ^1.5.0 route_generator: ^0.1.2
生成代碼
單次構(gòu)建
在項(xiàng)目根目錄中運(yùn)行flutter pub run build_runner build,可以在需要時(shí)為項(xiàng)目生成路由代碼。這會(huì)觸發(fā)一次性構(gòu)建,該構(gòu)建遍歷源文件,選擇相關(guān)文件,并為它們生成必要的路由代碼。雖然這很方便,但如果您不必每次在模型類(lèi)中進(jìn)行更改時(shí)都必須手動(dòng)構(gòu)建,那么你可以選擇持續(xù)構(gòu)建。
持續(xù)構(gòu)建
在項(xiàng)目根目錄中運(yùn)行flutter pub run build_runner watch來(lái)啟動(dòng)watcher,它可以使我們的源代碼生成過(guò)程更加方便。它會(huì)監(jiān)視項(xiàng)目文件中的更改,并在需要時(shí)自動(dòng)構(gòu)建必要的文件。
route_annotation
annotation | description |
---|---|
Router | 此注解用來(lái)標(biāo)志某個(gè)為 Flutter App 的類(lèi),并以此生成相應(yīng)的路由代碼 |
RoutePage | 此注解用來(lái)注解一個(gè)路由頁(yè)面 |
RouteParameter | 一個(gè)用來(lái)標(biāo)志頁(yè)面參數(shù)的注解,只為可選參數(shù)設(shè)計(jì)。用于 RoutePage 。 |
RouteField | 此注解用來(lái)標(biāo)志一個(gè)完全自定義的路由,被注解的對(duì)象必須作為路由頁(yè)面類(lèi)靜態(tài)字段 |
PageRouteBuilderFuntcion | 這個(gè)注解用來(lái)標(biāo)識(shí)一個(gè)路由頁(yè)面的 RouteFactory 靜態(tài)方法 |
RoutePageBuilderFunction | 這個(gè)注解用來(lái)標(biāo)識(shí)一個(gè)路由頁(yè)面的 RoutePageBuilder靜態(tài)方法 |
RouteTransitionBuilderFunction | 這個(gè)注解用來(lái)標(biāo)識(shí)一個(gè)路由頁(yè)面的 TransitionBuilder 靜態(tài)方法 |
RouteTransitionDurationField | 這個(gè)注解用來(lái)標(biāo)識(shí)一個(gè)自定義路由頁(yè)面的過(guò)渡時(shí)長(zhǎng) |
代碼示例
定義路由 App
@Router() class DemoApp extends StatefulWidget { @override _DemoAppState createState() => _DemoAppState(); } class _DemoAppState extends State<DemoApp> { @override Widget build(BuildContext context) { return MaterialApp( initialRoute: "/", onGenerateRoute: onGenerateRoute, ); } }
定義路由頁(yè)面
// isInitialRoute為true表示它將作為initial page @RoutePage(isInitialRoute: true) class HomePage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold(); } }
定義路由頁(yè)面參數(shù)
對(duì)于單個(gè)參數(shù)
@RoutePage(params: [RouteParameter("title")]) class OneArgumentPage extends StatelessWidget { final String title; const OneArgumentPage({Key key, this.title}) : super(key: key); @override Widget build(BuildContext context) { return Container(); } }
導(dǎo)航
Navigator.of(context).pushNamed( ROUTE_ONE_ARGUMENT_PAGE, arguments: "title is empty", );
注意事項(xiàng):
對(duì)于單個(gè)參數(shù)的路由,利用Navigator進(jìn)行導(dǎo)航的時(shí)候arguments即為原始參數(shù)。
對(duì)于多個(gè)參數(shù)
@RoutePage(params: [RouteParameter("title"), RouteParameter("subTitle")]) class TwoArgumentPage extends StatelessWidget { final String title; final String subTitle; TwoArgumentPage({this.title, Key key, this.subTitle}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold(); } }
導(dǎo)航
Navigator.of(context).pushNamed( ROUTE_TWO_ARGUMENT_PAGE, arguments: { "title": _titleController.text.isNotEmpty ? _titleController.text : "title is empty", "subTitle": _subTitleController.text.isNotEmpty ? _subTitleController.text : "sub title is empty", }, );
注意事項(xiàng):
對(duì)于多個(gè)參數(shù)的路由,利用Navigator進(jìn)行導(dǎo)航的時(shí)候arguments必須為Map<string,dynamic>。
如果你不需要自定義路由,以下部分,你可以什么都不用添加,就讓route_generator為你自動(dòng)生成相關(guān)代碼吧!
自定義路由(優(yōu)先級(jí):3)
這種方法自定義路由的優(yōu)先級(jí)最高,如果同時(shí)存在多種自定義路由選擇,該種方案最先被選擇。
@RoutePage() class CustomRoutePage extends StatelessWidget { @RouteField() static Map<String, RouteFactory> route = <String, RouteFactory>{ 'custom_route': (RouteSettings settings) => MaterialPageRoute(builder: (BuildContext context) => CustomRoutePage()), 'alias_route': (RouteSettings settings) => PageRouteBuilder( pageBuilder: (BuildContext context, Animation animation, Animation secondaryAnimation) => CustomRoutePage(), ), }; ... }
它會(huì)生成如下代碼:
Map<String, RouteFactory> _customRoutePage = CustomRoutePage.route;
自定義路由(優(yōu)先級(jí):2)
這種方法自定義路由的優(yōu)先級(jí)較低,如果同時(shí)存在多種自定義路由選擇,則按優(yōu)先級(jí)從大到小選擇。
@RoutePage() class CustomRoutePage extends StatelessWidget { @PageRouteBuilderFuntcion() static Route buildPageRoute(RouteSettings settings) => PageRouteBuilder( pageBuilder: (BuildContext context, Animation animation, Animation secondaryAnimation) => CustomRoutePage(), ); ... }
它會(huì)生成如下代碼:
Map<String, RouteFactory> _customRoutePage = <String, RouteFactory>{ 'custom_route_page': CustomRoutePage.buildPageRoute, };
自定義路由(優(yōu)先級(jí):1)
這種方法自定義路由的優(yōu)先級(jí)最低,如果同時(shí)存在多種自定義路由選擇,則按優(yōu)先級(jí)從大到小選擇。
@RoutePage() class CustomRoutePage extends StatelessWidget { // RoutePageBuilderFunction注解表明這個(gè)方法用來(lái)定義如何返回RoutePage // 它是可選的 @RoutePageBuilderFunction() static Widget buildPage(BuildContext context, Animation animation, Animation secondaryAnimation, RouteSettings settings) => CustomRoutePage(); // RouteTransitionBuilderFunction注解表明這個(gè)方法用來(lái)定義如何應(yīng)用動(dòng)畫(huà)過(guò)渡 // 它是可選的 @RouteTransitionBuilderFunction() static Widget buildTransitions( BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget child, RouteSettings settings) => child; // RouteTransitionDurationField注解表明這個(gè)字段用來(lái)定義頁(yè)面過(guò)渡時(shí)常長(zhǎng),默認(rèn)值為300 milliseconds // 它是可選的 @RouteTransitionDurationField() static Duration transitionDuration = Duration(milliseconds: 400); ... }
它會(huì)生成如下代碼:
Map<String, RouteFactory> _customRoutePage = <String, RouteFactory>{ 'custom_route_page': (RouteSettings settings) => PageRouteBuilder( pageBuilder: (context, animation, secondaryAnimation) => CustomRoutePage(), transitionsBuilder: (context, animation, secondaryAnimation, child) => CustomRoutePage.buildTransitions( context, animation, secondaryAnimation, child, settings), transitionDuration: CustomRoutePage.transitionDuration, ), };
注意事項(xiàng)
- 只允許有一個(gè)initalRoute
- initalRoute會(huì)忽略自定義路由名,但會(huì)生成名為ROUTE_HOME的路由名稱(chēng)常量。
- 所有自定義路由method或getter必須定義在路由所在類(lèi),且必須為static所修飾的和非私有的。
最終生成代碼
最終生成的文件名為FILENAME.route.dart
其中FILENAME是被Router注解的App類(lèi)所在的文件名。
// GENERATED CODE - DO NOT MODIFY BY HAND // ************************************************************************** // RouteGenerator // ************************************************************************** import 'package:flutter/material.dart'; import 'home_page.dart'; import 'custom_route_page.dart'; import 'custom_route_name_page.dart'; import 'second_page.dart'; import 'one_arguement_page.dart'; import 'two_arguement_page.dart'; const ROUTE_HOME = '/'; const ROUTE_CUSTOM_ROUTE_PAGE = 'custom_route_page'; const ROUTE_CUSTOM = 'custom'; const ROUTE_SECOND_PAGE = 'second_page'; const ROUTE_ONE_ARGUMENT_PAGE = 'one_argument_page'; const ROUTE_TWO_ARGUMENT_PAGE = 'two_argument_page'; RouteFactory onGenerateRoute = (settings) => Map.fromEntries([ ..._home.entries, ..._customRoutePage.entries, ..._custom.entries, ..._secondPage.entries, ..._oneArgumentPage.entries, ..._twoArgumentPage.entries, ])[settings.name](settings); Map<String, RouteFactory> _home = <String, RouteFactory>{ '/': (RouteSettings settings) => MaterialPageRoute( builder: (BuildContext context) => HomePage(), ), }; Map<String, RouteFactory> _customRoutePage = <String, RouteFactory>{ 'custom_route_page': (RouteSettings settings) => PageRouteBuilder( pageBuilder: (context, animation, secondaryAnimation) => CustomRoutePage.buildPage( context, animation, secondaryAnimation, settings), transitionsBuilder: (context, animation, secondaryAnimation, child) => CustomRoutePage.buildTransitions( context, animation, secondaryAnimation, child, settings), transitionDuration: CustomRoutePage.transitionDuration, ), }; Map<String, RouteFactory> _custom = <String, RouteFactory>{ 'custom': (RouteSettings settings) => MaterialPageRoute( builder: (BuildContext context) => CustomRoutePageName(), ), }; Map<String, RouteFactory> _secondPage = <String, RouteFactory>{ 'second_page': (RouteSettings settings) => MaterialPageRoute( builder: (BuildContext context) => SecondPage(), ), }; Map<String, RouteFactory> _oneArgumentPage = <String, RouteFactory>{ 'one_argument_page': (RouteSettings settings) => MaterialPageRoute( builder: (BuildContext context) => OneArgumentPage(title: settings.arguments), ), }; Map<String, RouteFactory> _twoArgumentPage = <String, RouteFactory>{ 'two_argument_page': (RouteSettings settings) => MaterialPageRoute( builder: (BuildContext context) => TwoArgumentPage( title: (settings.arguments as Map<String, dynamic>)['title'], subTitle: (settings.arguments as Map<String, dynamic>)['subTitle'], ), ), };
常見(jiàn)問(wèn)題
沒(méi)有生成路由文件
請(qǐng)檢查是否添加了Router注解
Example
獲取更詳細(xì)信息,請(qǐng)參閱example
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Flutter路由框架Fluro使用簡(jiǎn)介
- Flutter如何完成路由攔截,實(shí)現(xiàn)權(quán)限管理
- Flutter開(kāi)發(fā)中的路由參數(shù)處理
- Flutter app頁(yè)面路由以及路由攔截的實(shí)現(xiàn)
- 詳解Flutter的路由導(dǎo)航
- flutter 路由跳轉(zhuǎn)的實(shí)現(xiàn)示例
- flutter 自定義websocket路由的實(shí)現(xiàn)
- Flutter開(kāi)發(fā)之路由與導(dǎo)航的實(shí)現(xiàn)
- Flutter上線項(xiàng)目實(shí)戰(zhàn)記錄之路由篇
- Flutter 局部路由實(shí)現(xiàn)詳解
- Flutter路由的跳轉(zhuǎn)、動(dòng)畫(huà)和傳參詳解(最簡(jiǎn)單)
- Flutter 路由插件fluro的使用
相關(guān)文章
Android之用PopupWindow實(shí)現(xiàn)彈出菜單的方法詳解
本篇文章是對(duì)在Android中,用PopupWindow實(shí)現(xiàn)彈出菜單的方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-06-06Android自定義View實(shí)現(xiàn)loading動(dòng)畫(huà)加載效果
項(xiàng)目開(kāi)發(fā)中對(duì)Loading的處理是比較常見(jiàn)的,安卓系統(tǒng)提供的不太美觀,引入第三發(fā)又太麻煩,這時(shí)候自己定義View來(lái)實(shí)現(xiàn)這個(gè)效果。這篇文章主要介紹了Android自定義View實(shí)現(xiàn)loading動(dòng)畫(huà)加載效果,需要的朋友可以參考下2017-03-03詳解Android壁紙服務(wù)的啟動(dòng)過(guò)程
你有設(shè)置過(guò)手機(jī)的壁紙嗎,你知道壁紙是什么樣的程序它是怎么在后臺(tái)運(yùn)行的嗎?這篇文章主要介紹了詳解Android系統(tǒng)壁紙服務(wù)的啟動(dòng)過(guò)程2021-08-08android使用ExpandableListView控件實(shí)現(xiàn)小說(shuō)目錄效果的例子
這篇文章主要介紹了android使用ExpandableListView控件實(shí)現(xiàn)小說(shuō)目錄效果的例子,還可以實(shí)現(xiàn)二級(jí)列表展示效果,需要的朋友可以參考下2014-07-07Kotlin中ListView與RecyclerView的應(yīng)用講解
這篇文章主要介紹了Kotlin中ListView與RecyclerView的應(yīng)用講解,本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-09-09Android開(kāi)發(fā)之自定義View(視圖)用法詳解
這篇文章主要介紹了Android開(kāi)發(fā)之自定義View(視圖)用法,結(jié)合實(shí)例形式分析了Android自定義視圖的實(shí)現(xiàn)方法與使用注意事項(xiàng),需要的朋友可以參考下2016-10-10Android使用TextView實(shí)現(xiàn)無(wú)下劃線超鏈接的方法
這篇文章主要介紹了Android使用TextView實(shí)現(xiàn)無(wú)下劃線超鏈接的方法,結(jié)合實(shí)例形式分析了Android中TextView超鏈接去除下劃線的相關(guān)實(shí)現(xiàn)技巧與注意事項(xiàng),需要的朋友可以參考下2016-08-08