Repositorygit
這是一個簡單的 Flutter 路由生成庫,只須要少許的代碼,而後利用註解配合源代碼生成,自動生成路由表,省去手工管理路由代碼的煩惱。github
dependencies:
# Your other regular dependencies here
route_annotation: ^0.2.0
dev_dependencies:
# Your other dev_dependencies here
build_runner: ^1.5.0
route_generator: ^0.1.4
複製代碼
單次構建app
在項目根目錄中運行flutter pub run build_runner build
,能夠在須要時爲項目生成路由代碼。這會觸發一次性構建,該構建遍歷源文件,選擇相關文件,併爲它們生成必要的路由代碼。雖然這很方便,但若是您沒必要每次在模型類中進行更改時都必須手動構建,那麼你能夠選擇持續構建。less
持續構建ide
在項目根目錄中運行flutter pub run build_runner watch
來啓動watcher,它可使咱們的源代碼生成過程更加方便。它會監視項目文件中的更改,並在須要時自動構建必要的文件。動畫
annotation | description |
---|---|
Router |
此註解用來標誌某個爲 Flutter App 的類,並以今生成相應的路由代碼 |
RoutePage |
此註解用來註解一個路由頁面 |
RouteParameter |
一個用來標誌頁面參數的註解,只爲可選參數設計。用於 RoutePage 。 |
RouteField |
此註解用來標誌一個徹底自定義的路由,被註解的對象必須做爲路由頁面類靜態字段 |
PageRouteBuilderFuntcion |
這個註解用來標識一個路由頁面的 RouteFactory 靜態方法 |
RoutePageBuilderFunction |
這個註解用來標識一個路由頁面的 RoutePageBuilder 靜態方法 |
RouteTransitionBuilderFunction |
這個註解用來標識一個路由頁面的 TransitionBuilder 靜態方法 |
RouteTransitionDurationField |
這個註解用來標識一個自定義路由頁面的過渡時長 |
router new |
與Router() 相同 |
page new |
與RoutePage() 相同 |
initialPage new |
與RoutePage(isInitialRoute: true) 相同 |
routeField new |
與RouteField() 相同 |
routeBuilder new |
與PageRouteBuilderFuntcion() 相同 |
pageBuilder new |
與RoutePageBuilderFunction() 相同 |
transitionBuilder new |
與RouteTransitionBuilderFunction() 相同 |
transitionDuration new |
與RouteTransitionDurationField() 相同 |
@router
class DemoApp extends StatefulWidget {
@override
_DemoAppState createState() => _DemoAppState();
}
class _DemoAppState extends State<DemoApp> {
@override
Widget build(BuildContext context) {
return MaterialApp(
initialRoute: "/",
onGenerateRoute: onGenerateRoute,
);
}
}
複製代碼
@initialPage
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold();
}
}
複製代碼
對於單個參數ui
@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();
}
}
複製代碼
導航this
Navigator.of(context).pushNamed(
ROUTE_ONE_ARGUMENT_PAGE,
arguments: "title is empty",
);
複製代碼
注意事項:spa
對於單個參數的路由,利用Navigator進行導航的時候arguments
即爲原始參數。設計
對於多個參數
@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();
}
}
複製代碼
導航
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",
},
);
複製代碼
注意事項:
對於多個參數的路由,利用Navigator進行導航的時候arguments
必須爲Map<string,dynamic>
。
若是你不須要自定義路由,如下部分,你能夠什麼都不用添加,就讓route_generator爲你自動生成相關代碼吧!
這種方法自定義路由的優先級最高,若是同時存在多種自定義路由選擇,該種方案最早被選擇。
@page
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(),
),
};
...
}
複製代碼
它會生成以下代碼:
Map<String, RouteFactory> _customRoutePage = CustomRoutePage.route;
複製代碼
這種方法自定義路由的優先級較低,若是同時存在多種自定義路由選擇,則按優先級從大到小選擇。
@page
class CustomRoutePage extends StatelessWidget {
@pageBuilder
static Route buildPageRoute(RouteSettings settings) => PageRouteBuilder(
pageBuilder: (BuildContext context, Animation animation,
Animation secondaryAnimation) =>
CustomRoutePage(),
);
...
}
複製代碼
它會生成以下代碼:
Map<String, RouteFactory> _customRoutePage = <String, RouteFactory>{
'custom_route_page': CustomRoutePage.buildPageRoute,
};
複製代碼
這種方法自定義路由的優先級最低,若是同時存在多種自定義路由選擇,則按優先級從大到小選擇。
@page
class CustomRoutePage extends StatelessWidget {
// pageBuilder註解代表這個方法用來定義如何返回RoutePage
// 它是可選的
@pageBuilder
static Widget buildPage(BuildContext context, Animation animation,
Animation secondaryAnimation, RouteSettings settings) =>
CustomRoutePage();
// transitionBuilder註解代表這個方法用來定義如何應用動畫過渡
// 它是可選的
@transitionBuilder
static Widget buildTransitions(
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child,
RouteSettings settings) =>
child;
// transitionDuration註解代表這個字段用來定義頁面過渡時常長,默認值爲300 milliseconds
// 它是可選的
@transitionDuration
static Duration transitionDurations = Duration(milliseconds: 400);
...
}
複製代碼
它會生成以下代碼:
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.transitionDurations,
),
};
複製代碼
在須要支持從pubspec.yaml文件中的依賴包自動生成路由代碼的項目根目錄下,新建build.yaml文件,若是已經存在,則跳過這一步。
在文件中添加如下內容:
# If you are sure that you only run `flutter pub run build_runner build`,
# and don't run `flutter pub run build_runner watch`, then you can enable
# the following comment out content.
# targets:
# $default:
# builders:
# route_generator|route_collector:
# enabled: false
# If you also want to enable source code generation for the packages of
# dependencies in the pubspec.yaml, I think the following is what you need.
builders:
route_collector_all_packages:
import: 'package:route_generator/builder.dart'
builder_factories: ['routeCollectorAllPackages']
build_extensions: { '.dart': ['.collector_all_packages.dart'] }
auto_apply: all_packages
runs_before: ["route_generator|route_builder"]
build_to: cache
複製代碼
注意相同key部分請合併。
從新運行build_runner command便可
獲取更詳細信息,請參閱example
須要瞭解的是:pubspec.yaml dependencies packages 不支持watch模式持續生成路由代碼(第一次生成依然是有效的),可是你任然能夠在當前的application啓用watch模式。後期考慮支持。
因爲BuildStep不支持同一文件的不一樣輸出,即對於每個文件,它的輸出文件是限定了的,因此watch模式下,若是你修改了註解信息,那麼你可能須要使Route註解所在的文件刷新一次(必須使文件出現改動,而且保存,例如添加空行),纔會從新生成xxx.route.dart。正在盡力解決,目前方案須要手動刷新一次,若是你們有更好的方案,歡迎提出。
ROUTE_HOME
的路由名稱常量。最終生成的文件名爲FILENAME.route.dart 其中FILENAME是被Router註解的App類所在的文件名。
// GENERATED CODE - DO NOT MODIFY BY HAND
// **************************************************************************
// RouteGenerator
// **************************************************************************
import 'package:flutter/material.dart';
import 'package:example_library/example_library.dart';
import 'package:example/custom_route_name_page.dart';
import 'package:example/custom_route_page.dart';
import 'package:example/home_page.dart';
import 'package:example/one_arguement_page.dart';
import 'package:example/two_arguement_page.dart';
import 'package:example/second_page.dart';
const ROUTE_LIBRARY_PAGE = 'library_page';
const ROUTE_CUSTOM = 'custom';
const ROUTE_CUSTOM_ROUTE_PAGE = 'custom_route_page';
const ROUTE_HOME = '/';
const ROUTE_ONE_ARGUMENT_PAGE = 'one_argument_page';
const ROUTE_TWO_ARGUMENT_PAGE = 'two_argument_page';
const ROUTE_SECOND_PAGE = 'second_page';
RouteFactory onGenerateRoute = (settings) => Map.fromEntries([
..._libraryPage.entries,
..._custom.entries,
..._customRoutePage.entries,
..._home.entries,
..._oneArgumentPage.entries,
..._twoArgumentPage.entries,
..._secondPage.entries,
])[settings.name](settings);
Map<String, RouteFactory> _libraryPage = <String, RouteFactory>{
'library_page': (RouteSettings settings) => MaterialPageRoute(
builder: (BuildContext context) => LibraryPage(),
),
};
Map<String, RouteFactory> _custom = <String, RouteFactory>{
'custom': (RouteSettings settings) => MaterialPageRoute(
builder: (BuildContext context) => CustomRoutePageName(),
),
};
Map<String, RouteFactory> _customRoutePage = CustomRoutePage.route;
Map<String, RouteFactory> _home = <String, RouteFactory>{
'/': (RouteSettings settings) => MaterialPageRoute(
builder: (BuildContext context) => HomePage(),
),
};
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) {
final arguments = settings.arguments as Map<String, dynamic>;
return TwoArgumentPage(
title: arguments['title'],
subTitle: arguments['subTitle'],
);
},
),
};
Map<String, RouteFactory> _secondPage = <String, RouteFactory>{
'second_page': (RouteSettings settings) => MaterialPageRoute(
builder: (BuildContext context) => SecondPage(),
),
};
複製代碼
沒有生成路由文件
請檢查是否添加了Router註解
路由生成不完整
請嘗試運行如下命令:
獲取更詳細信息,請參閱example