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

Flutter利用注解生成可自定义的路由_第1张图片

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 {
  @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

如果你不需要自定义路由,以下部分,你可以什么都不用添加,就让route_generator为你自动生成相关代码吧!

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

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

@RoutePage()
class CustomRoutePage extends StatelessWidget {
  @RouteField()
  static Map route = {
    'custom_route': (RouteSettings settings) =>
        MaterialPageRoute(builder: (BuildContext context) => CustomRoutePage()),
    'alias_route': (RouteSettings settings) => PageRouteBuilder(
          pageBuilder: (BuildContext context, Animation animation,
                  Animation secondaryAnimation) =>
              CustomRoutePage(),
        ),
  };

  ...

}

它会生成如下代码:

Map _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 _customRoutePage = {
  '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 animation,
          Animation secondaryAnimation,
          Widget child,
          RouteSettings settings) =>
      child;

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

  ...

}

它会生成如下代码:

Map _customRoutePage = {
  '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 _home = {
  '/': (RouteSettings settings) => MaterialPageRoute(
        builder: (BuildContext context) => HomePage(),
      ),
};
Map _customRoutePage = {
  '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 _custom = {
  'custom': (RouteSettings settings) => MaterialPageRoute(
        builder: (BuildContext context) => CustomRoutePageName(),
      ),
};
Map _secondPage = {
  'second_page': (RouteSettings settings) => MaterialPageRoute(
        builder: (BuildContext context) => SecondPage(),
      ),
};
Map _oneArgumentPage = {
  'one_argument_page': (RouteSettings settings) => MaterialPageRoute(
        builder: (BuildContext context) =>
            OneArgumentPage(title: settings.arguments),
      ),
};
Map _twoArgumentPage = {
  'two_argument_page': (RouteSettings settings) => MaterialPageRoute(
        builder: (BuildContext context) => TwoArgumentPage(
              title: (settings.arguments as Map)['title'],
              subTitle:
                  (settings.arguments as Map)['subTitle'],
            ),
      ),
};

常见问题

  • 没有生成路由文件
  • 请检查是否添加了Router注解

最后

如果你看到了这里,觉得文章写得不错就给个赞呗!欢迎大家评论讨论!如果你觉得那里值得改进的,请给我留言。一定会认真查询,修正不足,定期免费分享技术干货。谢谢!

你可能感兴趣的:(移动互联网,Android学习,Android,Android程序员,Android开发,Flutter)