Day13 - Flutter - 路由导航

简介: Day13 - Flutter - 路由导航

概述


  • 路由管理
  • 路由基本使用
  • 命名路由使用(重点)
  • 页面跳转的拓展


一、路由管理



  • 1.1、认识Flutter路由路由的概念由来已久,包括网络路由、后端路由,到现在广为流行的前端路由。
  • 无论路由的概念如何应用,它的 核心是一个路由映射表
  • 比如:名字 detail 映射到 DetailPage 页面等
  • 有了这个映射表之后,我们就可以方便的根据名字来完成路由的转发(在前端表现出来的就是页面跳转)
  • 在Flutter中,路由管理主要有两个类:RouteNavigator
  • 1.2、RouteRoute:一个页面要想被路由统一管理,必须包装为一个Route
  • 官方的说法很清晰:An abstraction for an entry managed by a Navigator.
  • 但是Route是一个抽象类,所以它是不能实例化的
  • 在上面有一段注释,让我们查看 MaterialPageRoute 来使用


/// See [MaterialPageRoute] for a route that replaces the
/// entire screen with a platform-adaptive transition.
abstractclass Route<T> {
}
  • 事实上MaterialPageRoute并不是Route的直接子类:
  • MaterialPageRoute在不同的平台有不同的表现
  • Android平台,打开一个页面会从屏幕底部滑动到屏幕的顶部,关闭页面时从顶部滑动到底部消失
  • iOS平台,打开一个页面会从屏幕右侧滑动到屏幕的左侧,关闭页面时从左侧滑动到右侧消失
  • 当然,iOS平台我们也可以使用CupertinoPageRoute
  • 继承关系:MaterialPageRoute -> PageRoute -> ModalRoute -> TransitionRoute -> OverlayRoute -> Route
  • 1.3、NavigatorNavigator:管理所有的Route的Widget,通过一个Stack来进行管理的
  • 官方的说法也很清晰:A widget that manages a set of child widgets with a stack discipline.
    那么我们开发中需要手动去创建一个Navigator吗?
  • 并不需要,我们开发中使用的MaterialApp、CupertinoApp、WidgetsApp它们默认是有插入Navigator的
  • 所以,我们在需要的时候,只需要直接使用即可


Navigator.of(context)
  • Navigator有几个最常见的方法:


// 路由跳转:传入一个路由对象
Future<T> push<T extendsObject>(Route<T> route)
// 路由跳转:传入一个名称(命名路由)
Future<T> pushNamed<T extendsObject>(
    String routeName, {
         Object arguments,
})
// 路由返回:可以传入一个参数
bool pop<T extendsObject>([ T result ])


二、路由基本使用



  • 2.1、基本跳转
    我们来实现一个最基本跳转:
    创建首页页面,中间添加一个按钮,点击按钮跳转到详情页面
    创建详情页面,中间添加一个按钮,点击按钮返回到首页页面


image.png


  • 核心的跳转代码如下


// 跳转的按钮
RaisedButton(
    child: Text('跳转 书影集 详情'),
    onPressed: () {
       print('跳转 书影集 详情');
       _jumpToHomeDtail(context);
    },
),
// 按钮点击后的跳转
void _jumpToHomeDtail(BuildContext context) {
   Navigator.of(context).push(MaterialPageRoute(
       builder: (ctx) {
         return JKSubjectDetailPage();
       }
   ));
}

提示:JKSubjectDetailPage 是一个书影集的详情页面,代码如下

import 'package:flutter/material.dart';
class JKSubjectDetailPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(
            title: Text('书影集详情'),
         ),
         body: JKSubjectDetailContent(),
      );
   }
}
class JKSubjectDetailContent extends StatefulWidget {
    @override
    _JKSubjectDetailContentState createState() => _JKSubjectDetailContentState();
}
class _JKSubjectDetailContentState extends State<JKSubjectDetailContent> {
   @override
   Widget build(BuildContext context) {
      return Center(
         child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
               Text("书影集详情"),
                RaisedButton(
                  child: Text('返回上个界面'),
                  onPressed: () {
                     print('返回上个界面');
                     _popLastPage(context);
                  },
                ),
            ],
         ),
      );
   }
   // 返回上一个界面
   void _popLastPage(BuildContext context) {
       Navigator.of(context).pop();
   }
}


返回的拓展:

  • 1、自定义返回:Navigator.of(context).pop('这里可以加参数,参数的类型是泛型');
  • 2、监听返回按钮的点击(给Scaffold包裹一个WillPopScope
  • WillPopScope有一个onWillPop的回调函数,当我们点击返回按钮时会执行
  • 这个函数要求有一个Future的返回值:true:那么系统会自动帮我们执行pop操作;false:系统不再执行pop操作,需要我们自己来执行


WillPopScope(
   onWillPop: () {
      Navigator.of(context).pop("a back detail message");
      return Future.value(false);
   },
   child: Scaffold(
      appBar: AppBar(
          title: Text('书影集详情'),
      ),
      body: JKSubjectDetailContent(_detailmesaage),
   ),
);
  • 2.2、参数传递,下面我们以传递一个字符串为例在跳转过程中,我们通常可能会携带一些参数,比如
  • 书影集首页 跳到详情页,携带一条信息:a home message
  • 详情页返回首页,携带一条信息:a detail message
    我们需要在 详情页 定义一个属性 String,那么我们在类JKSubjectDetailPage 里面定义为 String _detailmesaage = '';
  • 首页跳转核心代码:
  • 在页面跳转时,会返回一个Future
  • 该Future会在详情页面调用pop时,回调对应的then函数,并且会携带结果


// 跳转的代码
void _jumpToHomeDtail(BuildContext context) {
    Future result = Navigator.of(context).push(MaterialPageRoute(
        builder: (ctx) {
            // 普通的跳转直接通过构造器传递即可
            return JKSubjectDetailPage('我是书影音首页传过去的数据');
        }
    ));
    result.then((value) {
        print('返回的结果是:$value');
    });
}
// 返回的核心代码
void _popLastPage(BuildContext context) {
    // pop<T extends Object>([ T result ]) 返回的结果是一个泛型
    Navigator.of(context).pop('我是返回的结果');
}


三、命名路由使用



  • 3.1. 基本跳转我们可以通过创建一个新的Route,使用Navigator来导航到一个新的页面,但是如果在应用中很多地方都需要导航到同一个页面(比如在开发中,首页、推荐、分类页都可能会跳到详情页),那么就会存在很多重复的代码。
  • 在这种情况下,我们可以使用命名路由(named route)
  • 命名路由是将名字和路由的映射关系,在一个地方进行统一的管理
  • 有了命名路由,我们可以通过Navigator.pushNamed() 方法来跳转到新的页面
  • 命名路由在哪里管理呢?可以放在MaterialApp的 initialRoute 和 routes 中
  • initialRoute:设置应用程序从哪一个路由开始启动,设置了该属性,就不需要再设置home属性了
  • routes:定义名称和路由之间的映射关系,类型为Map<String, WidgetBuilder>
  • 修改MaterialApp中的代码:



return MaterialApp(
    title: 'FlutterDemo',
    theme: ThemeData(
       primaryColor: Colors.blue,
       splashColor: Colors.transparent,
       // 点击的水波纹设置为无色
       highlightColor: Colors.transparent
    ),
    // 启动要显示的界面
    // home: JKMainPage(),
    initialRoute: JKRouter.initialRoute,
    // 路由列表
    routes: JKRouter.routes,
    // 当routes里面找不到的时候,就会到这里根据名字找到对应的页面
    onGenerateRoute: JKRouter.generateRoute,
    // 路由占不到的错误界面
    onUnknownRoute: JKRouter.unknownRoute,
);
  • 我们定义一个 routers.dart 文件,


class JKRouter {
   // 路由数组
   static final Map<String, WidgetBuilder> routes = {
      JKMainPage.routeName: (ctx) => JKMainPage(),
      JKHomePage.routeName: (ctx) => JKHomePage(),
      JKSubjectDetailPage.routeName: (ctx) => JKSubjectDetailPage(),
   };
   // 首先展示的界面
   static final String initialRoute = JKMainPage.routeName;
   // 当routes里面找不到的时候,就会到这里根据名字找到对应的页面
   static final RouteFactory generateRoute = (settings) {
      if (settings.name == JKSubjectDetailPage.routeName) {
         return MaterialPageRoute(
           builder: (ctx) {
             return JKSubjectDetailPage();
           }
         );
       }
       return null;
    };
    // 根据路由找不到界面的时候做展示的错误页面
    static final RouteFactory unknownRoute = (settings) {
        return MaterialPageRoute(
            builder: (ctx) {
               return JKUnknownPage();
            }
        );
    };
}
  • 修改跳转的代码:


Future result = Navigator.of(context).pushNamed(JKSubjectDetailPage.routeName, arguments: '我是参数');
   result.then((value) {
      setState(() {
      _message = value;
   });
   print('返回的结果是:$value');
});
  • 在开发中,为了让每个页面对应的routeName统一,我们通常会在每个页面中定义一个路由的常量来使用:下面以 书影音的详情页为例


class JKSubjectDetailPage extends StatefulWidget {
    static const String routeName = "/subjectdetail";
}
  • 以后有新的页面我们就修改 router.dart 文件 和新的页面增加 routeName(如上面的代码)


// 路由数组
static final Map<String, WidgetBuilder> routes = {
   JKMainPage.routeName: (ctx) => JKMainPage(),
   JKHomePage.routeName: (ctx) => JKHomePage(),
   JKSubjectDetailPage.routeName: (ctx) => JKSubjectDetailPage(),
};


  • 3.2、参数传递
    因为通常命名路由,我们会在定义路由时,直接创建好对象,比如JKSubjectDetailPage()
    那么,命名路由如果有参数需要传递呢?
    pushNamed时,如何传递参数:


_onPushTap(BuildContext context) {
     Navigator.of(context).pushNamed(JKSubjectDetailPage.routeName, arguments: "a home message of naned route");
}
  • 在JKSubjectDetailPage中,如何获取到参数呢?在build方法中ModalRoute.of(context)可以获取到传递的参数


Widget build(BuildContext context) {
   // 1.获取数据
   final message = ModalRoute.of(context).settings.arguments;
}


四、页面跳转的拓展



  • 4.1、模态跳转和push跳转


void _jumpToHomeDtail(BuildContext context) {
      Navigator.of(context).push(MaterialPageRoute(
          builder: (ctx) {
             return JKProfileDetail();
          },
          fullscreenDialog: false
      ));
}

提示: fullscreenDialog: false

  • true: 从底部显示下个页面,iOS里面叫 模态跳转
  • false: 从右边推出显示下个页面,iOS里面叫 push 跳转


  • 4.2、PageRouteBuilder 渐变跳转


void _jumpToHomeDtail(BuildContext context) {
    Navigator.of(context).push(PageRouteBuilder(
       // 渐变所需要的时间
       transitionDuration: Duration(seconds: 3),
       pageBuilder: (ctx, animarion1, animation2) {
           return FadeTransition(
             // 透明度
             opacity: animarion1,
             child: JKProfileDetail(),
           );
       }
   ));
}


到此的代码

目录
相关文章
|
9月前
|
Dart Android开发 UED
带你读《深入浅出Dart》二十七、Flutter路由管理
带你读《深入浅出Dart》二十七、Flutter路由管理
105 0
Flutter Getx 路由 until 方法帮助你跳转指定路由
不少同学都会问我,这样一个场景,当我点击商品列表,进入商品页,点击购买,支付成功后,想返回商品页,或者我的中心的订单列表。怎么做,这中间跨度了 n 个路由。 我不只一次的推荐 GetX 的 until 方法,和 offNamedUntil 方法。 我写了个 demo 今天我们就一起来看下这两个方法如何使用。
1281 0
Flutter Getx 路由 until 方法帮助你跳转指定路由
|
12天前
flutter 导航组件 AppBar (含顶部选项卡TabBar,抽屉菜单 drawer ,自定义导航图标)
flutter 导航组件 AppBar (含顶部选项卡TabBar,抽屉菜单 drawer ,自定义导航图标)
11 1
|
12天前
|
Android开发
Flutter路由跳转参数处理小技巧
Flutter路由跳转参数处理小技巧
|
2月前
|
安全 Go 数据安全/隐私保护
Flutter开发笔记:Flutter路由技术
Flutter开发笔记:Flutter路由技术
531 0
|
2月前
|
前端开发 开发者 iOS开发
【Flutter前端技术开发专栏】Flutter中的路由管理与页面跳转
【4月更文挑战第30天】本文介绍了Flutter的路由管理与页面跳转,包括基本和命名路由管理。基本路由使用`Navigator`的`push`和`pop`方法,如`MaterialPageRoute`和`CupertinoPageRoute`。命名路由则通过路由表注册名称进行跳转,如`Navigator.pushNamed`。此外,还展示了如何通过构造函数、`arguments`和`PageRouteBuilder`进行路由传值。掌握这些知识能提升Flutter开发效率。
【Flutter前端技术开发专栏】Flutter中的路由管理与页面跳转
|
2月前
|
BI
Flutter笔记:路由观察者
Flutter笔记:路由观察者
184 0
|
2月前
|
UED
Flutter之自定义路由切换动画
Flutter之自定义路由切换动画 在Flutter中,我们可以通过Navigator来实现路由管理,包括路由的跳转和返回等。默认情况下,Flutter提供了一些简单的路由切换动画,但是有时候我们需要自定义一些特殊的动画效果来提高用户体验。本文将介绍如何在Flutter中实现自定义的路由切换动画。
118 0
|
2月前
|
API
Flutter状态管理终极方案GetX第一篇——路由
Flutter状态管理终极方案GetX第一篇——路由 GetX是Flutter中一个非常流行的状态管理库,它不仅提供了简单易用的状态管理功能,还可以帮助我们方便地管理路由。在这篇文章中,我们将介绍如何使用GetX来实现路由管理。
206 0
Flutter仿写微信导航栏快速实现页面导航
Flutter仿写微信导航栏快速实现页面导航