Flutter利用注解生成可自定義的路由的實(shí)現(xiàn)
route_generator是什么
這是一個(gè)簡(jiǎn)單的 Flutter 路由生成庫,只需要少量的代碼,然后利用注解配合源代碼生成,自動(dòng)生成路由表,省去手工管理路由代碼的煩惱。
特性
- 自定義路由名稱
- 自定義路由動(dòng)畫
- 自定義路由參數(shù)
- 自定義路由邏輯
依賴
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)文件,并為它們生成必要的路由代碼。雖然這很方便,但如果您不必每次在模型類中進(jìn)行更改時(shí)都必須手動(dòng)構(gòu)建,那么你可以選擇持續(xù)構(gòu)建。
持續(xù)構(gòu)建
在項(xiàng)目根目錄中運(yùn)行flutter pub run build_runner watch來啟動(dòng)watcher,它可以使我們的源代碼生成過程更加方便。它會(huì)監(jiān)視項(xiàng)目文件中的更改,并在需要時(shí)自動(dòng)構(gòu)建必要的文件。
route_annotation
| annotation | description |
|---|---|
| Router | 此注解用來標(biāo)志某個(gè)為 Flutter App 的類,并以此生成相應(yīng)的路由代碼 |
| RoutePage | 此注解用來注解一個(gè)路由頁面 |
| RouteParameter | 一個(gè)用來標(biāo)志頁面參數(shù)的注解,只為可選參數(shù)設(shè)計(jì)。用于 RoutePage 。 |
| RouteField | 此注解用來標(biāo)志一個(gè)完全自定義的路由,被注解的對(duì)象必須作為路由頁面類靜態(tài)字段 |
| PageRouteBuilderFuntcion | 這個(gè)注解用來標(biāo)識(shí)一個(gè)路由頁面的 RouteFactory 靜態(tài)方法 |
| RoutePageBuilderFunction | 這個(gè)注解用來標(biāo)識(shí)一個(gè)路由頁面的 RoutePageBuilder靜態(tài)方法 |
| RouteTransitionBuilderFunction | 這個(gè)注解用來標(biāo)識(shí)一個(gè)路由頁面的 TransitionBuilder 靜態(tài)方法 |
| RouteTransitionDurationField | 這個(gè)注解用來標(biāo)識(shí)一個(gè)自定義路由頁面的過渡時(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,
);
}
}
定義路由頁面
// isInitialRoute為true表示它將作為initial page
@RoutePage(isInitialRoute: true)
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold();
}
}
定義路由頁面參數(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è)方法用來定義如何返回RoutePage
// 它是可選的
@RoutePageBuilderFunction()
static Widget buildPage(BuildContext context, Animation animation,
Animation secondaryAnimation, RouteSettings settings) =>
CustomRoutePage();
// RouteTransitionBuilderFunction注解表明這個(gè)方法用來定義如何應(yīng)用動(dòng)畫過渡
// 它是可選的
@RouteTransitionBuilderFunction()
static Widget buildTransitions(
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child,
RouteSettings settings) =>
child;
// RouteTransitionDurationField注解表明這個(gè)字段用來定義頁面過渡時(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的路由名稱常量。
- 所有自定義路由method或getter必須定義在路由所在類,且必須為static所修飾的和非私有的。
最終生成代碼
最終生成的文件名為FILENAME.route.dart
其中FILENAME是被Router注解的App類所在的文件名。
// 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'],
),
),
};
常見問題
沒有生成路由文件
請(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開發(fā)中的路由參數(shù)處理
- Flutter app頁面路由以及路由攔截的實(shí)現(xiàn)
- 詳解Flutter的路由導(dǎo)航
- flutter 路由跳轉(zhuǎn)的實(shí)現(xiàn)示例
- flutter 自定義websocket路由的實(shí)現(xiàn)
- Flutter開發(fā)之路由與導(dǎo)航的實(shí)現(xiàn)
- Flutter上線項(xiàng)目實(shí)戰(zhàn)記錄之路由篇
- Flutter 局部路由實(shí)現(xiàn)詳解
- Flutter路由的跳轉(zhuǎn)、動(dòng)畫和傳參詳解(最簡(jiǎn)單)
- Flutter 路由插件fluro的使用
相關(guān)文章
Android自定義控件實(shí)現(xiàn)UC瀏覽器語音搜索效果
這篇文章主要為大家詳細(xì)介紹了Android自定義控件實(shí)現(xiàn)UC瀏覽器語音搜索效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-04-04
android 仿微信demo——微信主界面實(shí)現(xiàn)
本系列文章主要介紹了微信小程序-閱讀小程序?qū)嵗╠emo),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧,希望能給你們提供幫助2021-06-06
android通過代碼的形式來實(shí)現(xiàn)應(yīng)用程序的方法
因?yàn)閼?yīng)用程序的安裝與卸載模塊在android系統(tǒng)中已經(jīng)寫好了,所以我們只需要激活就行了2013-10-10
android 版本檢測(cè) Android程序的版本檢測(cè)與更新實(shí)現(xiàn)介紹
做個(gè)網(wǎng)站的安卓客戶端,用戶安裝到自己手機(jī)上,如果我出了新版本怎么辦呢?要有版本更新功能,感興趣的朋友可以了解下2013-01-01
Android開發(fā)中優(yōu)秀的app 異常處理機(jī)制
這篇文章主要介紹了Android開發(fā)中優(yōu)秀的app 異常處理機(jī)制 的相關(guān)資料,需要的朋友可以參考下2015-12-12
Android編程實(shí)現(xiàn)VideoView循環(huán)播放功能的方法
這篇文章主要介紹了Android編程實(shí)現(xiàn)VideoView循環(huán)播放功能的方法,結(jié)合簡(jiǎn)單實(shí)例形式分析了Android使用VideoView實(shí)現(xiàn)多媒體播放功能的操作技巧,需要的朋友可以參考下2017-02-02

