Flutter利用注解生成可自定义的路由的实现

时间:2022-07-27
本文章向大家介绍Flutter利用注解生成可自定义的路由的实现,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

route_generator是什么

这是一个简单的 Flutter 路由生成库,只需要少量的代码,然后利用注解配合源代码生成,自动生成路由表,省去手工管理路由代码的烦恼。

特性

  • 自定义路由名称
  • 自定义路由动画
  • 自定义路由参数
  • 自定义路由逻辑

依赖

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

生成代码

单次构建

在项目根目录中运行flutter pub run build_runner build,可以在需要时为项目生成路由代码。这会触发一次性构建,该构建遍历源文件,选择相关文件,并为它们生成必要的路由代码。虽然这很方便,但如果您不必每次在模型类中进行更改时都必须手动构建,那么你可以选择持续构建。

持续构建

在项目根目录中运行flutter pub run build_runner watch来启动watcher,它可以使我们的源代码生成过程更加方便。它会监视项目文件中的更改,并在需要时自动构建必要的文件。

route_annotation

annotation

description

Router

此注解用来标志某个为 Flutter App 的类,并以此生成相应的路由代码

RoutePage

此注解用来注解一个路由页面

RouteParameter

一个用来标志页面参数的注解,只为可选参数设计。用于 RoutePage 。

RouteField

此注解用来标志一个完全自定义的路由,被注解的对象必须作为路由页面类静态字段

PageRouteBuilderFuntcion

这个注解用来标识一个路由页面的 RouteFactory 静态方法

RoutePageBuilderFunction

这个注解用来标识一个路由页面的 RoutePageBuilder静态方法

RouteTransitionBuilderFunction

这个注解用来标识一个路由页面的 TransitionBuilder 静态方法

RouteTransitionDurationField

这个注解用来标识一个自定义路由页面的过渡时长

代码示例

定义路由 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();
 }
}

定义路由页面参数

对于单个参数

@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();
 }
}

导航

Navigator.of(context).pushNamed(
 ROUTE_ONE_ARGUMENT_PAGE,
 arguments: "title is empty",
);

注意事项:

对于单个参数的路由,利用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为你自动生成相关代码吧!

自定义路由(优先级:3)

这种方法自定义路由的优先级最高,如果同时存在多种自定义路由选择,该种方案最先被选择。

@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(),
    ),
 };

 ...

}

它会生成如下代码:

Map<String, RouteFactory  _customRoutePage = CustomRoutePage.route;

自定义路由(优先级:2)

这种方法自定义路由的优先级较低,如果同时存在多种自定义路由选择,则按优先级从大到小选择。

@RoutePage()
class CustomRoutePage extends StatelessWidget {
 @PageRouteBuilderFuntcion()
 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,
};

自定义路由(优先级:1)

这种方法自定义路由的优先级最低,如果同时存在多种自定义路由选择,则按优先级从大到小选择。

@RoutePage()
class CustomRoutePage extends StatelessWidget {
 // RoutePageBuilderFunction注解表明这个方法用来定义如何返回RoutePage
 // 它是可选的
 @RoutePageBuilderFunction()
 static Widget buildPage(BuildContext context, Animation animation,
     Animation secondaryAnimation, RouteSettings settings) = 
   CustomRoutePage();

 // RouteTransitionBuilderFunction注解表明这个方法用来定义如何应用动画过渡
 // 它是可选的
 @RouteTransitionBuilderFunction()
 static Widget buildTransitions(
     BuildContext context,
     Animation<double  animation,
     Animation<double  secondaryAnimation,
     Widget child,
     RouteSettings settings) = 
   child;

 // RouteTransitionDurationField注解表明这个字段用来定义页面过渡时常长,默认值为300 milliseconds
 // 它是可选的
 @RouteTransitionDurationField()
 static Duration transitionDuration = Duration(milliseconds: 400);

 ...

}

它会生成如下代码:

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,
   ),
};

注意事项

  • 只允许有一个initalRoute
  • initalRoute会忽略自定义路由名,但会生成名为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'],
      ),
   ),
};

常见问题

没有生成路由文件

请检查是否添加了Router注解

Example

获取更详细信息,请参阅example

以上就是本文的全部内容,希望对大家的学习有所帮助。