flutter 路由全解

本教程前半部分属于入门,后半部分属于进阶

1.routes 和navigator 的关系 ?

大部分应用程序都包含多个页面,并希望用户能从当前屏幕平滑过渡到另一个屏幕。移动应用程序通常通过被称为“屏幕”或“页面”的全屏元素来显示内容Flutter 中,这些元素被称为路由(Route),它们由导航器(Navigator)控件管理。导航器管理着路由对象的堆栈并提供管理堆栈的方法,如 Navigator.pushNavigator.pop,通过路由对象的进出栈来使用户从一个页面跳转到另一个页面。

2. 怎么使用 ?

(1)push方法

设置一个构造函数 (第二个page的初始方法)

 final String title;
 Page({this.title});

跳转传值

   Navigator.push(context,
        MaterialPageRoute(builder: (context) => Page(title: "题目")));

返回

   Navigator.pop(context);
(2) pushName方法

在初始化APP的地方MaterialApp,设置一个路由列表

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(  // 这个是标记
      home: MainPage(),
      debugShowCheckedModeBanner: false,
      routes: {  // 就是它
        '/page':(context) => Page()
       '/home':(context) => Home()
      },
    );
  }
}

在需要跳转的时候

    Navigator.pushNamed(context, '/page');

这里有一个问题就是使用 Navigator.pushNamed 时无法直接给新页面传参数,目前官方还没有标准解决方案,我知道的方案是在 onGenerateRoute 回调方法和arguments参数设置。

完整事例

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(

             //监听导航routes 数据  PassArguments
      onGenerateRoute: (settings) {

//对比路由名称
        if (settings.name == PassArgumentsScreen.routeName) {
          final ScreenArguments args = settings.arguments;

           //返回  MaterialPageRoute 
          return MaterialPageRoute(
            builder: (context) {
              return PassArgumentsScreen(
                title: args.title,
                message: args.message,
              );
            },
          );
        }
      },
      title: 'Navigation with Arguments',
      home: HomeScreen(),
    );
  }
}

class HomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Home Screen'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
           
                //设置一个button
            RaisedButton(
              child: Text("Navigate to screen that extracts arguments"),
              onPressed: () {
              

             // 设置传值参数  arguments  /settings

                Navigator.push(
                  context,
                  MaterialPageRoute(
                    builder: (context) => ExtractArgumentsScreen(),
             
                    settings: RouteSettings(
                      arguments: ScreenArguments(
                        'Extract Arguments Screen',
                        'This message is extracted in the build method.',
                      ),
                    ),
                  ),
                );
              },
            ),
       
   
            RaisedButton(
              child: Text("Navigate to a named that accepts arguments"),
              onPressed: () {
              

                Navigator.pushNamed(
                  context,
                  PassArgumentsScreen.routeName,
                  arguments: ScreenArguments(
                    'Accept Arguments Screen',
                    'This message is extracted in the onGenerateRoute function.',
                  ),
                );
              },
            ),
          ],
        ),
      ),
    );
  }
}

// push界面
class ExtractArgumentsScreen extends StatelessWidget {
  static const routeName = '/extractArguments';

  @override
  Widget build(BuildContext context) {

 final ScreenArguments args = ModalRoute.of(context).settings.arguments;

    return Scaffold(
      appBar: AppBar(
        title: Text(args.title),
      ),
      body: Center(
        child: Text(args.message),
      ),
    );
  }
}

//接受界面
class PassArgumentsScreen extends StatelessWidget {
  static const routeName = '/passArguments';

  final String title;
  final String message;


  // MaterialApp widget.
  const PassArgumentsScreen({
    Key key,
    @required this.title,
    @required this.message,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(title),
      ),
      body: Center(
        child: Text(message),
      ),
    );
  }
}

// 设置任意参数
class ScreenArguments {
  final String title;
  final String message;

  ScreenArguments(this.title, this.message);
}

看懂了上面的原理当然可以简化了。
定义要接受参数的界面的时候

// 定义接受的构造函数
final arguments;
Page({this.arguments};

在上一界面传值的时候

Navigator.pushNamed(context,'/search',argument:{
    'id':'1123';   // 参数随便写
    'name':'sunny'
})

当然路由配置的时候要这样

final routes = {
    'page':(context,{arguments})=>Page(arguments:arguments);
     'page':(context,{arguments})=>Page(arguments:arguments);
     'page':(context,{arguments})=>Page(arguments:arguments);
     'page':(context,{arguments})=>Page(arguments:arguments);  
}
final  String  name = setting.name;
final  Function  pagContentBuilder = this.routes[name];

当然你也可以吧参数和路由名称都封装到一个类中去 。说说思路,全局单利路由文件设置好 ,设置路由对象 ,对象的个数和名称提前固定 ,可以根据名称随时更改需要传值的参数 。 在界面跳转前更改参数 ,传入参数 ,在界面跳转后接受数据。
面对逆向的时候还可以加上加密措施和代码混淆

//Routes.dart
import 'pa/material'  import '所有界面'
final routes = {
    'page':(context,{arguments})=>Page(arguments:arguments);
     'page':(context,{arguments})=>Page(arguments:arguments);
     'page':(context,{arguments})=>Page(arguments:arguments);
     'page':(context,{arguments})=>Page(arguments:arguments);  
}
// 生成路由回调的的固定写法 
var onGenerateroute = (RounteSettings setting){
   final  String  name = setting.name;
   final  Function  pagContentBuilder = routes[name];
   if (pagContentBuilder != null){
      if(setting.arguments != null){

        final  Route route = MaterialpageRoute(
         buider:(context) => 
               PageContentBuilder(context,arguments:setting.arguments);
         )
         return route;
      }else{
           final  Route route = MaterialpageRoute(
         buider:(context) => 
               PageContentBuilder(context);
         )
         return route;
      }

   }
 
}


3.路由的命名规范 ?

树状结构命名法

'\' #主页
'\home' #主页 下 home界面
'\my' #主页 下 my界面
'\home\name' #主页 下 home界面 下name界面

3.initialRoute 的作用 ?

initialRoute 同样是MaterialApp 的属性 ,也就是相当于iOS里面的appdelegate部分,在全局只能设置一次 。 在routes里面设置的路由都可以通过initialRoute来设置,也就是第一次启动app时候,我们的初始界面是那个。

路由的返回功能

Navigator.of(context).pop();

返回根路由/ 替换路由 在跳转的时候使用替换路由,在返回的时候会直接返回到根目录

Navigator.of(context).pushReplacementNamed('/firstPage');

或者直接返回根的代码/ 没有的话直接更改界面 。

Navigator.of(context).pushAndRemoveUntil(
    // 中间的界面置为空,直到我们返回的页面。
    newMaterialPageRutes(builder:context)=>new Tab bar(index : 1),
    (route)=>route==null;
)

(看到这里的都很厉害,给你们点终极福利)

fluro的封装使用

国外都流行用这个现在,下面是最权威的封装

1设置一个全局的router,

形式多样,单例都可以,此处就放到Application类中了。

//application.dart
import 'package:fluro/fluro.dart';

class Application {
  static Router router;
}
2. 设置router 信息

引入handle文件,具体界面目录

//routers.dart
import 'package:fluro/fluro.dart';
import 'package:flutter/material.dart';
import 'package:~/route_handlers.dart';

class Routes {
  static String root = '/';
//添加路由命名
  static String chatDetail = '/chat';

  static void configureRoutes(Router router) {
    router.notFoundHandler = new Handler(
      handlerFunc: (BuildContext context, Map> params) {
        print('Route was not found.');
      }
    );
    router.define(root, handler: rootHandler);
//一条一条往后加处理方式
    router.define(chatDetail, handler: chatDetailHandler);
  }
}
3. 设置routerHandle 信息

具体每个页面怎么处理都在这个文件中

//route_handlers.dart
import 'package:fluro/fluro.dart';
import 'package:flutter/material.dart';
import 'package:flutter_whatsapp/src/home.dart';


// 一条一条往后加,此处没做任何处理
var rootHandler = new Handler(
  handlerFunc: (BuildContext context, Map> params) {
    return new Home();
  }
);

 //此处解析了一个参数profileId
var chatDetailHandler = new Handler(
    handlerFunc: (BuildContext context, Map> params) {
      int profileId = int.tryParse(params['profileId']?.first) ?? null;
// 此处调用构造方法
      return new DetailChatScreen(
        id: profileId,  
      );
    }
);

4.使用

MaterialApp中初始化


import 'package:fluro/fluro.dart';
import 'package:flutter/material.dart';
import 'package:config/application.dart';
import 'package:config/routes.dart';
import 'package:/src/home.dart';
import 'package:/src/values/colors.dart';



class FlutteredApp extends StatefulWidget {
  @override
  _FlutteredAppState createState() => _FlutteredAppState();
}

class _FlutteredAppState extends State {

  _FlutteredAppState() {
    final router = new Router();
    Routes.configureRoutes(router);
    Application.router = router;
  }

  /// Default theme.
  static final ThemeData _defaultTheme = new ThemeData(
    primaryColor: primaryColor,
    accentColor: Colors.white,
    scaffoldBackgroundColor: scaffoldBgColor,
  );

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'setting',
      theme: _defaultTheme,
      onGenerateRoute: Application.router.generator,
    );
  }
}

调用

Application.router.navigateTo(
      context,
      "${Router.chatDetail}?profileId=${id}",
      transition: TransitionType.inFromRight,
    );

返回

  Navigator.of(context).pop();

你可能感兴趣的:(flutter 路由全解)