本文示例代码地址
Flutter 安装包中会包含代码和 assets 资源两部分,Assets 是会打包到程序安装包中的,可在运行时访问。常见类型的 assets 包括静态数据,如 json ,配置文件,图片,MP3,gif 等。
加载图片
例如加载一张图片,在 Flutter 中使用 pubspec.yaml 文件来管理所需要的文件
- 在加载图片之前,需要在根目录下创建一个文件夹,里面存放图片,以及它所对应分辨率的图片
如上图,创建了 images 文件夹,然后放入图片,并创建对应分辨率的文件夹,将图片放进去即可 注意:flutter 默认是必须要创建 2.0x 和 3.0x,至于4.0x,可自行选择
- 图片准备好之后,就可以通过 pubspec.yaml 文件进行配置
flutter:
uses-material-design: true
assets:
- images/icon.png
- images/2.0x/icon.png
- images/3.0x/icon.png
- images/4.0x/icon.png
- 接着就可以显示图片了
class AssetsLoad extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return _AssetsLoadState();
}
}
class _AssetsLoadState extends State<AssetsLoad> {
var imageID = "";
void uploadImage() {
setState(() {
imageID = "images/icon.png";
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("资源加载"),
),
body: Column(
children: [
Center(
child: Container(
child: Image.asset("$imageID", fit: BoxFit.cover),
width: 100,
height: 100,
),
),
RaisedButton(
onPressed: () {
uploadImage();
},
child: Text("加载图片"),
)
],
),
);
}
}
效果如下所示
分辨率2.0x,3.0x,4.0x
当设备像素比(device pixel ratio) < 1 时候,images/icon.png
的图片将会被使用。 当设备像素比 1 < (device pixel ratio) < 2 时候,images/2.0x/icon.png
的图片将会被使用。 当设备像素比 2 < (device pixel ratio) < 3 时候,images/3.0x/icon.png
的图片将会被使用,
当 > 3 的时候,4.0x 中的图片会被调用
Flutter 最终会根据设备像素比例,去获取对应分辨率的图片
pubspec.yaml 中 asset 部分中的每一项应与实际文件相对应,但是主资源除外,当主资源缺少某个文件时,会按照分辨率从低到高的顺序去选择。
Asset 变体(variant)
构建过程支持变体概念:不同版本的 asset 可能会显示在不同的上下文中。在 pubspec.yaml
的 assets 部分指定路径时,构建过程中,会在相邻的子目录去查找具有相同名称的任何文件,这些文件随后会与指定的 asset 一起被包含在 asset bundle 中。
例如
代码语言:javascript复制.../pubspec.yaml
.../images/icon.png
.../images/2.0x/icon.png
复制代码
然后在 pubspec.yaml
中,只需要包含:
flutter:
assets:
- images/icon.png
复制代码
那么这两个 images/icon.png 和 images/2.0x/icon.png 都将包含在 asset bundle 中。前者被认为是 main asset(主资源),后者被认为是一种变体(variant)
在选择设备当前分辨率时,Flutter 会用到 asset 变体,将来,Flutter 可能会将这种机制扩展到本地化,阅读提示等方面
因此,在上面加载图片中,pubspec.yaml
文件可以直接使用如下写法:
flutter:
uses-material-design: true
assets:
- images/icon.png
复制代码
加载依赖包中的资源图片
代码语言:javascript复制new Image.asset('icons/heart.png', package: 'my_icons')
复制代码
例如,如果要加载一个名字为 fancy_backgrounds 的包,那么他的资源文件应该是
…/lib/backgrounds/background1.png
…/lib/backgrounds/background2.png
…/lib/backgrounds/background3.png
而对应的在 pubspec.yaml 中也应该进行声明
代码语言:javascript复制flutter:
assets:
- packages/fancy_backgrounds/backgrounds/background1.png
复制代码
加载文本assets
- 通过
rootBundle
对象加载,每个 Flutter 都有一个 rootBundle 对象,通过他可以轻松访问主资源包,直接使用package:flutter/services.dart
中全局的 rootBundle 对象来加载 assets 即可 - 通过
DefaultAssetBundle
来加载,建议使用DefaultAssetBundle
来获取当前 BuildContext 的 AssetBundle 。 这种方法不是使用应用程序构建默认的 asset bundle,而是使用父级 widget 在运行时动态替换不同的 AssetBundle,这对本地化或测试场景会很有用
通常可以使用 DefalutAssetBundle.of()
在应用运行时来间接加载 asset(例如 json 文件),而在 widget 上下文之外,或者其他 AssetBundle 不可用时, 可以使用 routBundle
直接加载 asset
class AssetsLoad extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return _AssetsLoadState();
}
}
class _AssetsLoadState extends State<AssetsLoad> {
var imageID = "";
var text = "";
void uploadImage() {
setState(() {
imageID = "images/icon.png";
});
}
Future<String> loadText() async {
return await rootBundle.loadString("assets/file.txt");
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("资源加载"),
),
body: Column(
children: [
//.......
Container(
child: Center(
child: Text(
text,
textAlign: TextAlign.center,
),
),
width: 100,
height: 100,
),
RaisedButton(
onPressed: () {
loadText().then((value) {
setState(() {
text = value;
});
});
},
child: Text("加载文本"),
)
],
),
);
}
}
复制代码
如上所示,调用 loadText 可以获取到文件中的内容,注意,该文件需要在 pubspec.yaml
中进行声明
效果如下:
设置 APP 图标
更新 Flutter 应用程序启动图标的方式与在本机 Android 或 iOS 中 更新图标的方式相同
- Android
在 flutter 根目录中,找到
.../android/app/src/main/res
目录,例包含了各种资源文件夹,如 mipmap 等,找到名字为 ic_launcher.png 的图片,然后替换即可,注意,需要遵守每种屏幕密度(dpi)的建议图标大小标准即可
- iOS
在 Flutter 项目中,导航到
.../ios/Runner
。该目录中Assets.xcassets/AppIcon.appiconset
已经包含占位符图片。主需要将他们替换为适当大小的图片,保留原始文件名称
更新启动页
在 Flutter 框架加载时,Flutter 会使用本地机制绘制启动项,此启动页将持续到 Flutter 渲染应用程序的第一帧时
这意味着如果你不在应用程序的 main() 方法中调用
runApp
函数 (或者更具体的说,如果你不调用window.render
去响应window.onDrawFrame
) 的话,启动屏幕将永远显示
- Android
要将启动屏幕 (splash screen) 添加到您的 Flutter 程序,请导航至
.../android/app/src/main
,在res/drawable/launch_background.xml
,通过自定义 drawable 来实现自定义启动页面(你也可以直接换一张图片)
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="?android:colorBackground" />
<!-- You can insert your own image assets here -->
<item>
<bitmap
android:gravity="center"
android:src="@drawable/launch_image" />
</item>
</layer-list>
- iOS
要将图片添加到 启动屏幕,请导航至
.../ios/Runner
。在Assets.xcassets/**LaunchImage.imageset
。 ,拖入图片,并命名为LaunchImage.png
、LaunchImage@2x.png
、LaunchImage@3x.png
。 如果你使用不同的文件名,那您还必须更新同一目录中的Contents.json
文件,图片的具体尺寸可以查看苹果官方的标准。 您也可以通过打开Xcode完全自定义storyboard。在Project Navigator中导航到Runner/Runner然后通过打开Assets.xcassets拖入图片,或者通过在LaunchScreen.storyboard中使用Interface Builder进行自定义
问题
1,使用本地图片之后,需要重新运行项目,而不是启用热重载,如果使用热重载,可能会导致错误,或者是图片加载不出来
2,在 pubspec.yaml 中,一定要注意规范,避免出现多余的空格等 ,否则可能会出现异常
3,在 pubspec.yaml 中需要将所有使用到的图片全部声明出来,虽然在知道变体以后一张图片只需要写一次,但是仍然会非常麻烦,这个时候可以使用一个相对路径来标识,如:
代码语言:javascript复制flutter:
uses-material-design: true
assets:
- images/
复制代码
参考自Flutter实战(书籍)