路由
路由管理,就是管理页面之间如何跳转,通常也可被称为导航管理。Flutter中的路由管理和原生开发类似,无论是Android还是iOS,导航管理都会维护一个路由栈,路由入栈(push)操作对应打开一个新页面,路由出栈(pop)操作对应页面关闭操作,而路由管理主要是指如何来管理路由栈。
距离:
1 | class NewRoute extends StatelessWidget { |
1 | FlatButton( |
MaterialPageRoute
MaterialPageRoute可以针对不同平台,实现与平台页面切换动画风格一致的路由切换动画:
- 对于Android,当打开新页面时,新的页面会从屏幕底部滑动到屏幕顶部;当关闭页面时,当前页面会从屏幕顶部滑动到屏幕底部后消失,同时上一个页面会显示到屏幕上。
- 对于iOS,当打开页面时,新的页面会从屏幕右侧边缘一致滑动到屏幕左边,直到新页面全部显示到屏幕上,而上一个页面则会从当前屏幕滑动到屏幕左侧而消失;当关闭页面时,正好相反,当前页面会从屏幕右侧滑出,同时上一个页面会从屏幕左侧滑入。
1 | MaterialPageRoute({ |
builder
是一个WidgetBuilder类型的回调函数,它的作用是构建路由页面的具体内容,返回值是一个widget。我们通常要实现此回调,返回新路由的实例。settings
包含路由的配置信息,如路由名称、是否初始路由(首页)。maintainState
:默认情况下,当入栈一个新路由时,原来的路由仍然会被保存在内存中,如果想在路由没用的时候释放其所占用的所有资源,可以设置maintainState
为false。fullscreenDialog
表示新的路由页面是否是一个全屏的模态对话框,在iOS中,如果fullscreenDialog
为true
,新页面将会从屏幕底部滑入(而不是水平方向)。
Navigator
Navigator
是一个路由管理的组件,它提供了打开和退出路由页方法。
**push:**将给定的路由入栈(即打开新的页面),返回值是一个Future
对象,用以接收新路由出栈(即关闭)时的返回数据。
**pop:**将栈顶路由出栈,result
为页面关闭时返回给上一个页面的数据。
Navigator
还有很多其它方法,如Navigator.replace
、Navigator.popUntil
等
Navigator.push(BuildContext context, Route route)等价于
Navigator.of(context).push(Route route)
1 | return Center( |
1 | TipRoute({ |
TipRoute会传入一个text值。
命名路由
所谓“命名路由”(Named Route)即有名字的路由,我们可以先给路由起一个名字,然后就可以通过路由名字直接打开新的路由了,这为路由管理带来了一种直观、简单的方式。
注册路由表
路由表的注册方式很简单,然后在MyApp
类的build
方法中找到MaterialApp
,添加routes
属性,代码如下:
1 | MaterialApp( |
注册首页只需在路由表中注册一下首页路由,然后将其名字作为MaterialApp
的initialRoute
属性值即可,该属性决定应用的初始路由页是哪一个命名路由。
通过路由名打开新路由页
要通过路由名称来打开新路由,可以使用Navigator
的pushNamed
方法:
1 | Future pushNamed(BuildContext context, String routeName,{Object arguments}) |
1 | onPressed: () { |
命名路由参数传递
在路由页通过RouteSetting
对象获取路由参数:
1 | class EchoRoute extends StatelessWidget { |
在打开路由时传递参数
1 | Navigator.of(context).pushNamed("new_page", arguments: "hi"); |
适配
如果路由注册时需要参数:
1 | MaterialApp( |
路由生成钩子
用Navigator.pushNamed(...)
打开命名路由时,如果指定的路由名在路由表中已注册,则会调用路由表中的builder
函数来生成路由组件;如果路由表中没有注册,才会调用onGenerateRoute
来生成路由。onGenerateRoute
回调签名如下:
1 | Route<dynamic> Function(RouteSettings settings) |
有了onGenerateRoute
回调,要实现上面控制页面权限的功能就非常容易:我们放弃使用路由表,取而代之的是提供一个onGenerateRoute
回调,然后在该回调中进行统一的权限控制,如:
1 | MaterialApp( |
这种方式可以在启动每个路由时都统一处理操作。
包管理
1 | name: flutter_in_action |
各个字段的意义:
name
:应用或包名称。description
: 应用或包的描述、简介。version
:应用或包的版本号。dependencies
:应用或包依赖的其它包或插件。dev_dependencies
:开发环境依赖的工具包(而不是flutter应用本身依赖的包)。flutter
:flutter相关的配置选项。
Pub仓库
Pub是Google官方的Dart Packages仓库
添加到依赖项列表:
1 | dependencies: |
添加完之后一般需要下载:单击右上角的 Packages get 。
引入包:
1 | import 'package:english_words/english_words.dart'; |
使用包:
1 | final wordPair = new WordPair.random(); |
其它依赖方式
依赖本地包
1 | dependencies: |
路径可以是相对的,也可以是绝对的。
依赖Git
1 | dependencies: |
上面假定包位于Git存储库的根目录中。如果不是这种情况,可以使用path参数指定相对位置,例如:
1 | dependencies: |
资源管理
Flutter APP安装包中会包含代码和 assets(资源)两部分。Assets是会打包到程序安装包中的,可在运行时访问。常见类型的assets包括静态数据(例如JSON文件)、配置文件、图标和图片(JPEG,WebP,GIF,动画WebP / GIF,PNG,BMP和WBMP)等。
指定 assets
Flutter也使用pubspec.yaml
文件来管理应用程序所需的资源,举个例子:
1 | flutter: |
assets
指定应包含在应用程序中的文件,asset的实际目录可以是任意文件夹
Asset 变体
在pubspec.yaml
的assets部分中指定asset路径时,构建过程中,会在相邻子目录中查找具有相同名称的任何文件。这些文件随后会与指定的asset一起被包含在asset bundle中。
例如,如果应用程序目录中有以下文件:
- …/pubspec.yaml
- …/graphics/my_icon.png
- …/graphics/background.png
- …/graphics/dark/background.png
- …etc.
然后pubspec.yaml
文件中只需包含:
1 | flutter: |
那么这两个graphics/background.png
和graphics/dark/background.png
都将包含在您的asset bundle中。前者被认为是main asset (主资源),后者被认为是一种变体(variant)。在选择匹配当前设备分辨率的图片时,Flutter会使用到asset变体。
加载 assets
加载文本assets
- 通过
rootBundle
对象加载:每个Flutter应用程序都有一个rootBundle
对象, 通过它可以轻松访问主资源包,直接使用package:flutter/services.dart
中全局静态的rootBundle
对象来加载asset即可。 - 通过
DefaultAssetBundle
加载:建议使用DefaultAssetBundle
来获取当前BuildContext的AssetBundle。 这种方法不是使用应用程序构建的默认asset bundle,而是使父级widget在运行时动态替换的不同的AssetBundle,这对于本地化或测试场景很有用。
通常,可以使用DefaultAssetBundle.of()
在应用运行时来间接加载asset(例如JSON文件),而在widget上下文之外,或其它AssetBundle
句柄不可用时,可以使用rootBundle
直接加载这些asset,例如:
1 | import 'dart:async' show Future; |
加载图片
AssetImage
可以将asset的请求逻辑映射到最接近当前设备像素比例(dpi)的asset。为了使这种映射起作用,必须根据特定的目录结构来保存asset:
- …/image.png
- …/Mx/image.png
- …/Nx/image.png
- …etc.
其中M和N是数字标识符,对应于其中包含的图像的分辨率,也就是说,它们指定不同设备像素比例的图片。
主资源默认对应于1.0倍的分辨率图片。看一个例子:
- …/my_icon.png
- …/2.0x/my_icon.png
- …/3.0x/my_icon.png
1.8的设备上,会选择2.0x,2.7的设备上会选择3.0x
加载示例:
1 | Widget build(BuildContext context) { |
可以使用Image.asset()
方法:
1 | Widget build(BuildContext context) { |
依赖包中的资源图片
要加载依赖包中的图像,必须给AssetImage
提供package
参数。
例如,假设您的应用程序依赖于一个名为“my_icons”的包,它具有如下目录结构:
- …/pubspec.yaml
- …/icons/heart.png
- …/icons/1.5x/heart.png
- …/icons/2.0x/heart.png
- …etc.
1 | new AssetImage('icons/heart.png', package: 'my_icons') |
或
1 | new Image.asset('icons/heart.png', package: 'my_icons') |
打包包中的 assets
如果在pubspec.yaml
文件中声明了期望的资源,它将会打包到相应的package中。特别是,包本身使用的资源必须在pubspec.yaml
中指定。
包也可以选择在其lib/
文件夹中包含未在其pubspec.yaml
文件中声明的资源。在这种情况下,对于要打包的图片,应用程序必须在pubspec.yaml
中指定包含哪些图像。 例如,一个名为“fancy_backgrounds”的包,可能包含以下文件:
- …/lib/backgrounds/background1.png
- …/lib/backgrounds/background2.png
- …/lib/backgrounds/background3.png
要包含第一张图像,必须在pubspec.yaml
的assets部分中声明它:
1 | flutter: |
特定平台 assets
设置APP图标
更新Flutter应用程序启动图标的方式与在本机Android或iOS应用程序中更新启动图标的方式相同。
更新启动页
与在本机Android或iOS应用程序中更新启动图标的方式相同。