首页
学习
活动
专区
圈层
工具
发布

Flutter开发-路由

前言

管理多个页面时有两个核心概念和类:RouteNavigator

一个route是一个屏幕或页面的抽象,Navigator是管理route的Widget。

Navigator可以通过route入栈和出栈来实现页面之间的跳转。

Flutter的路由有两种方式

  • 基本路由
  • 命名路由

基本路由就相当于Android和iOS原生的页面跳转方式。

命名路由就相当于VUE的Router插件一样,这种方式耦合性更低,功能更强大。

在一个项目中两种方式是可以同时使用的,推荐使用命名路由的方式,项目的结构看起来比较清晰。

## 基本路由

跳转

代码语言:javascript
复制
Navigator.push(context,
    MaterialPageRoute(builder: (context) {
  return HomePage();
}));

替换形式跳转

适用于登录后跳转到主页面 不能再返回到登录页面

代码语言:javascript
复制
Navigator.pushReplacement(context,
    MaterialPageRoute(builder: (context) {
  return HomePage();
}));

关闭页面

代码语言:javascript
复制
Navigator.pop(context);

除了页面关闭用这个方法,窗口的关闭也是用这个方法,因为Flutter的Dialog的实现方式就是基于路由的。

### 返回根路由

代码语言:javascript
复制
Navigator.of(context).pushAndRemoveUntil(
   new MaterialPageRoute(builder: (context) => new HomePage()),
   (route) => route == null
);

路由传值

页面

代码语言:javascript
复制
class MyHomePage extends StatefulWidget {
  // 类的构造器,用来接收传递的值
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;   // 用来储存传递过来的值

  @override
  _MyHomePageState createState() => new _MyHomePageState();
}

传入值的方式

代码语言:javascript
复制
new MyHomePage(title: '带参数跳转')

## 命名路由

路由定义与初始化

路由定义

代码语言:javascript
复制
import 'package:flutter/material.dart';
import 'package:qggj_android/page/HomePage.dart';
import 'package:qggj_android/page/LoginPage.dart';

final Map<String, Function> routes = {
  '/': (context) => LoginPage(),
  '/home': (context) => HomePage(),
  '/kaoqin': (context) => KaoqinPage(),
  '/kaoqin_detail': (context) => KaoqinDetailPage(),
  '/kaoqin_history': (context) => KaoqinHistoryPage(),
};

var onGenerateRoute = (RouteSettings settings) {
  final String name = settings.name;
  final Function pageContentBuilder = routes[name];
  if (pageContentBuilder != null) {
    if (settings.arguments != null) {
      final Route route = MaterialPageRoute(
          builder: (context) =>
              pageContentBuilder(context, arguments: settings.arguments));
      return route;
    } else {
      final Route route =
          MaterialPageRoute(builder: (context) => pageContentBuilder(context));
      return route;
    }
  }
};

初始化路由

代码语言:javascript
复制
import 'package:flutter/material.dart';
import 'route/MyRoutes.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: '',
        debugShowCheckedModeBanner: false,
        theme: ThemeData(
          primarySwatch: Colors.blue,
          visualDensity: VisualDensity.adaptivePlatformDensity,
        ),
        initialRoute: '/',
        onGenerateRoute: onGenerateRoute);
  }
}

跳转

不带参数

代码语言:javascript
复制
Navigator.pushNamed(context, "/home");

带参数

代码语言:javascript
复制
Navigator.pushNamed(context, '/home', arguments: {"id": 20});

替换形式跳转

代码语言:javascript
复制
Navigator.pushReplacementNamed(context, "/home");

关闭页面

代码语言:javascript
复制
Navigator.pop(context);

除了页面关闭用这个方法,窗口的关闭也是用这个方法,因为Flutter的Dialog的实现方式就是基于路由的。

### 返回根路由

代码语言:javascript
复制
//flutter 登录后跳转到根路由
Navigator.of(context).pushNamedAndRemoveUntil(
    '/home',
    (route) => false,//true 保留当前栈  false 销毁所有 只留下HomePage
    arguments: {
    },
);

路由传值

接收参数页面

代码语言:javascript
复制
import 'package:flutter/material.dart';

class SearchPage extends StatelessWidget {
  
  final arguments;
  SearchPage({this.arguments});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar:AppBar(
        title: Text("搜索页面"),
      ) ,
      body: Text("搜索页面内容区域${arguments != null ? arguments['keyword'] : ''}"),
    );
  }
}

跳转传参

代码语言:javascript
复制
//路由跳转
Navigator.pushNamed(context, '/search',arguments: {
    "keyword":"资讯"
});

导航返回拦截

为了避免用户误触返回按钮而导致APP退出,在很多APP中都拦截了用户点击返回键的按钮,然后进行一些防误触判断,比如当用户在某一个时间段内点击两次时,才会认为用户是要退出(而非误触)。Flutter中可以通过WillPopScope来实现返回按钮拦截,我们看看WillPopScope的默认构造函数:

代码语言:javascript
复制
const WillPopScope({
  ...
  @required WillPopCallback onWillPop,
  @required Widget child
})

onWillPop是一个回调函数,当用户点击返回按钮时被调用(包括导航返回按钮及Android物理返回按钮)。该回调需要返回一个Future对象,如果返回的Future最终值为false时,则当前路由不出栈(不会返回);最终值为true时,当前路由出栈退出。我们需要提供这个回调来决定是否退出。

示例

为了防止用户误触返回键退出,我们拦截返回事件。当用户在1秒内点击两次返回按钮时,则退出;如果间隔超过1秒则不退出,并重新记时。

代码如下:

代码语言:javascript
复制
import 'package:flutter/material.dart';

class LoginPage extends StatefulWidget {
  @override
  LoginPageState createState() {
    return new LoginPageState();
  }
}

class LoginPageState extends State<LoginPage> {
  DateTime _lastPressedAt; //上次点击时间

  @override
  Widget build(BuildContext context) {
    return new WillPopScope(
        onWillPop: () async {
          if (_lastPressedAt == null ||
              DateTime.now().difference(_lastPressedAt) > Duration(seconds: 1)) {
            //两次点击间隔超过1秒则重新计时
            _lastPressedAt = DateTime.now();
            return false;
          }
          return true;
        },
        child: Scaffold(
          body: Text("这是登录页面"),
        )
    );
  }
}
举报
领券