接上一章搭建开发环境,这章学习Flutter中,路由、包、资源的管理。
1、路由管理
Flutter中的路由名为route,可以理解为Android中的activity。路由管理也就是指route之间的跳转、传值、回传数据。主要由Navigator控制,Navigator是一个路由管理的组件,它提供了打开和退出路由页方法。Navigator通过一个栈来管理活动路由集合。通常当前屏幕显示的页面就是栈顶的路由。Navigator提供了一系列方法来管理路由栈,在此我们只介绍其最常用的两个方法:
Future push(BuildContext context, Route route)
将给定的路由入栈(即打开新的页面),返回值是一个Future对象,用以接收新路由出栈(即关闭)时的返回数据。
bool pop(BuildContext context, [ result ])
将栈顶路由出栈,result为页面关闭时返回给上一个页面的数据。
1.1 路由跳转
比如我们想要跳转到一个叫做New Route的路由,基本写法就是这样的:
NavigatorState navigatorState = Navigator.of(context);
prefix0.MaterialPageRoute materialPageRoute = new MaterialPageRoute(builder: (context){return new NewRoute();});
navigatorState.push(materialPageRoute);
//这段代码和下面的Android中的启动一个Activity很像
Intent intent = new Intent();
intent.setClass(this,MainActivity.class);
startActivity(intent);
再来看下简写的区别:
Navigator.of(context)
.push(new MaterialPageRoute(builder: (context) {
return new NewRoute();
}));
----------------------------------------------------------------
startActivity(new Intent(this,MainActivity.class));
但是这样写还是很麻烦,Android中也有封装好的启动一个activity的方式,看下封装的代码:
ActivityUtils.startActivity(MainActivity.class);
这样来说一行代码就能用普通方式启动一个activity。
那Flutter中也有这么简单的启动方式,就是命名路由,所谓命名路由就是先给路由起个名字,等我们想要启动路由的时候,根据这个名字就可以启动这个路由了。以下是如何实现的代码:
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.orange,
),
//注册路由表
routes: {
"路由名称": (context) => new NewRoute(),
--省略其他路由注册
},
);
上面代码中的routes其实就是一个它是一个Map,key为路由的名字,是个字符串;value是个builder回调函数,用于生成相应的路由widget。我们在通过路由名字打开新路由时,应用会根据路由名字在路由表中查找到对应的WidgetBuilder回调函数,然后调用该回调函数生成路由widget并返回。这样我们来看看启动一个命名路由有多简单:
Navigator.pushNamed(context, “路由名称”);
一行代码就可以了,很简单。
1.2 路由传值
如何启动一个路由的时候把数据传过去?
看官方的函数:
static Future<T> pushNamed<T extends Object>(
BuildContext context,
String routeName, {
Object arguments,
}) {
return Navigator.of(context).pushNamed<T>(routeName, arguments: arguments);
}
其实就是上面的pushNamed函数,第一个参数是上下文的context,第二个参数是要启动的路由名称,第三个参数就是要传递的数据。看下具体怎么实现:
Navigator.pushNamed(context, "路由名称",arguments: "要传递的数据");
就是再加一个参数,这个参数可以是string可以是int,只要是object的子类就行。那启动的路由怎么接收传递过去的数据呢,看代码:
class 路由名称 extends StatelessWidget {
@override
Widget build(BuildContext context) {
// 下面这行代码就是接收传递数据的代码。
var data = ModalRoute.of(context).settings.arguments;
--省略其他代码
}
1.3 路由数据回传
如果启动一个路由并且接收此路由关闭时传递回来的数据,怎么实现。这时候就用到开始说的pop函数了
看下官网代码:
static bool pop<T extends Object>(BuildContext context, [ T result ]) {
return Navigator.of(context).pop<T>(result);
}
此函数就是把栈顶的路由也就是当前页面给移除栈,第一个参数是上下文context,第二个参数就是要回传的数据。看下具体实现:
RaisedButton(
onPressed: () => Navigator.pop(context, "NewRoute返回的数据"),
child: Text("返回"),
)
这样这个路由就会关闭且回传数据,那如何接收回传的数据,也很简单,把前面启动的代码稍加改动就可以了,看代码:
onPressed: () async {
var pushNamed = await Navigator.pushNamed(
context, StringsConst.ROUTE_NEW,
arguments: "来自main的数据");
print("NewRoute返回的数据:$pushNamed");
}
这里使用async/await来等待页面的关闭,pushNamed函数会返回一个var,就是路由回传的数据。
注意:这种方式只有在点击自己添加的返回按钮才会有回传数据,点击AppBar上的返回或者手机自带的返回键返回上一个路由是接收不到数据的,如何实现无论怎么返回都能返回数据,书里没说,后面再看有没有其他办法。
1.4启动新路由关闭当前路由
如果想要启动一个新路由的同时并关闭当前路由,使用下面这三个函数任何一个都可以:
Navigator.of(context).pushReplacementNamed("路由名称");
--------------------------------------------------------------------------------------
Navigator.of(context).pushReplacement(
new MaterialPageRoute(builder: (context) {
return new NewRoute();
}));
---------------------------------------------------------------------------------------
Navigator.popAndPushNamed(context, "路由名称");
1.5 启动新路由并关闭之前所有路由
还有一种情况,就是当用户退出登录后,到重新登录的路由,这样我们需要关闭所有已有的路由,并启动登录路由,这时候使用下面这个函数:
Future<T> pushNamedAndRemoveUntil<T extends Object>(
String newRouteName,
RoutePredicate predicate, {
Object arguments,
}) {
return pushAndRemoveUntil<T>(_routeNamed<T>(newRouteName, arguments: arguments), predicate);
}
第一个参数:要启动的路由名称。
第二个参数:暂时还不清楚。
第三个参数:要传递的数据。
看下具体实现代码:
Navigator.of(context).pushNamedAndRemoveUntil("路由名称", (Route<dynamic> route) => false);
还有一个函数是关闭所有的路由:
void popUntil(RoutePredicate predicate) {
while (!predicate(_history.last))
pop();
}
2 包管理
包其实就是指一些公共的库或SDK,我们想要使用这些公共的包就需要先对这些包有个统一的管理。介绍包管理前先介绍下Flutter中的pubspec.yaml文件,这个文件就是项目的配置文件,来对项目和包进行管理配置。看下这个文件中的默认代码都是什么意思:
# 应用或包名称。
name: first_flutter_app
# 应用或包简介、描述。
description: A new Flutter application.
# 应用或包的版本号。
version: 1.0.0+1
environment:
sdk: ">=2.1.0 <3.0.0"
# 应用或包依赖的其它包或插件。
dependencies:
flutter:
sdk: flutter
# 类iOS风格图标
cupertino_icons: ^0.1.2
# 常用英文单词以及一些实用功能
english_words: ^3.1.5
# 开发环境依赖的工具包(而不是flutter应用本身依赖的包)。
dev_dependencies:
flutter_test:
sdk: flutter
# flutter相关的配置选项。
flutter:
uses-material-design: true
上面是一些简单的介绍,其中的:english_words: ^3.1.5。就是我们用到的一个公共包。
这些包都是在pub.dev统一管理的,我们可以在这上面找到我们需要的包。
比如english_words:
Example是使用例子,Installing是如何安装。
第一步:将english_words: ^3.1.5添加到pubspec.yaml中。
第二步:点击右上角的pub get。
第三步:在使用的route中导包:import ‘package:english_words/english_words.dart’。
3 资源管理
3.1 图片适配
资源管理是指一些图标、图片、字体、html等等的一些管理,这里先简单学一下图标的管理,其他的还要放到后面实际应用的时候再具体的学习怎么使用。
图片资源管理其实也是在pubspec.yaml中注册,Flutter会根据设备屏幕的像素密度来选择加载不同的图片,那不同大小的图片怎么管理,系统才会选择到正确的图片呢,在assets中创建不同倍率的文件夹用来存放对应大小的图片,如图:
然后在pubspec.yaml中进行注册:
然后就可以使用,使用的使用不用写2x\3x,系统会自动根据分辨率选择对应的图片:
Image.asset(
"assets/wxr.jpg",
width: 200,
height: 200,
fit: BoxFit.cover,
),
3.2 修改APP图标和启动页
Android修改APP的图标需要替换图中的图标文件
iOS修改APP图标需要替换下图中的文件:
Android修改启动页需要修改下图中的文件:
iOS修改启动页需要修改下图中的文件: