添加资产和图片
Flutter 应用可以包含代码和资产(有时称为资源)。资产是与你的应用打包并部署的文件,可在运行时访问。常见的资产类型包括静态数据(例如 JSON 文件)、配置文件、图标和图片(JPEG、WebP、GIF、动画 WebP/GIF、PNG、BMP 和 WBMP)。
指定资产
#Flutter 使用位于项目根目录的 pubspec.yaml
文件来识别应用所需的资产。
这是一个例子
flutter:
assets:
- assets/my_icon.png
- assets/background.png
要包含某个目录下的所有资产,请在目录名末尾加上 /
字符
flutter:
assets:
- directory/
- directory/subdirectory/
资产打包
#flutter
部分的 assets
子节指定了应包含在应用中的文件。每个资产都由其所在位置的显式路径(相对于 pubspec.yaml
文件)标识。资产声明的顺序无关紧要。实际使用的目录名(第一个示例中的 assets
或上述示例中的 directory
)无关紧要。
在构建过程中,Flutter 会将资产放入一个名为资产包 (asset bundle) 的特殊存档中,应用在运行时会从中读取。
构建时资产文件的自动转换
#Flutter 支持在构建应用时使用 Dart 包来转换资产文件。为此,请在 pubspec 文件中指定资产文件和转换器包。要了解如何执行此操作以及编写自己的资产转换包,请参阅构建时转换资产。
加载资产
#你的应用可以通过 AssetBundle
对象访问其资产。
资产包上的两个主要方法允许你根据逻辑键从包中加载字符串/文本资产 (loadString()
) 或图片/二进制资产 (load()
)。逻辑键映射到构建时在 pubspec.yaml
文件中指定的资产路径。
加载文本资产
#每个 Flutter 应用都有一个 rootBundle
对象,用于方便地访问主资产包。可以使用 package:flutter/services.dart
中的 rootBundle
全局静态对象直接加载资产。
然而,建议使用 DefaultAssetBundle
获取当前 BuildContext
的 AssetBundle
,而不是应用中内置的默认资产包;这种方法允许父 widget 在运行时替换不同的 AssetBundle
,这对于本地化或测试场景非常有用。
通常,你会使用 DefaultAssetBundle.of()
从应用的运行时 rootBundle
中间接加载资产,例如 JSON 文件。
在 Widget
上下文之外,或者当无法获取 AssetBundle
的句柄时,你可以使用 rootBundle
直接加载此类资产。例如
import 'package:flutter/services.dart' show rootBundle;
Future<String> loadAsset() async {
return await rootBundle.loadString('assets/config.json');
}
加载图片
#要加载图片,请在 widget 的 build()
方法中使用 AssetImage
类。
例如,你的应用可以从上一个示例中的资产声明加载背景图片
return const Image(image: AssetImage('assets/background.png'));
分辨率感知图片资产
#Flutter 可以根据当前设备的设备像素比加载相应分辨率的图片。
AssetImage
会将逻辑请求的资产映射到与当前设备的设备像素比最接近的那个。
为了使这种映射起作用,资产应按照特定的目录结构进行组织
.../image.png
.../Mx/image.png
.../Nx/image.png
...etc.
其中 M 和 N 是数字标识符,对应于其中包含的图片的标称分辨率。换句话说,它们指定了图片所针对的设备像素比。
在此示例中,image.png
被视为主资产,而 Mx/image.png
和 Nx/image.png
被视为变体。
主资产假定对应于 1.0 的分辨率。例如,考虑名为 my_icon.png
的图片的以下资产布局
.../my_icon.png (mdpi baseline)
.../1.5x/my_icon.png (hdpi)
.../2.0x/my_icon.png (xhdpi)
.../3.0x/my_icon.png (xxhdpi)
.../4.0x/my_icon.png (xxxhdpi)
在设备像素比为 1.8 的设备上,会选择资产 .../2.0x/my_icon.png
。对于设备像素比为 2.7 的设备,会选择资产 .../3.0x/my_icon.png
。
如果在 Image
widget 上未指定渲染图片的宽度和高度,则使用标称分辨率来缩放资产,使其占用与主资产相同的屏幕空间,但分辨率更高。也就是说,如果 .../my_icon.png
是 72x72 像素,那么 .../3.0x/my_icon.png
应该是 216x216 像素;但如果未指定宽度和高度,它们都将渲染为 72x72 逻辑像素。
分辨率感知图片资产的打包
#你只需要在 pubspec.yaml
的 assets
部分指定主资产或其父目录。Flutter 会为你打包变体。每个条目都应对应一个真实文件,主资产条目除外。如果主资产条目不对应真实文件,则分辨率最低的资产将用作设备像素比低于该分辨率的设备的备用。但是,该条目仍应包含在 pubspec.yaml
清单中。
任何使用默认资产包加载图片的行为都将继承分辨率感知能力。(如果你使用一些低级类,例如 ImageStream
或 ImageCache
,你还会注意到与缩放相关的参数。)
包依赖中的图片资产
#要从包依赖项加载图片,必须向 AssetImage
提供 package
参数。
例如,假设你的应用依赖于一个名为 my_icons
的包,该包具有以下目录结构
.../pubspec.yaml
.../icons/heart.png
.../icons/1.5x/heart.png
.../icons/2.0x/heart.png
...etc.
要加载图片,请使用
return const AssetImage('icons/heart.png', package: 'my_icons');
包本身使用的资产也应如上所述使用 package
参数获取。
包资产的打包
#如果所需的资产在包的 pubspec.yaml
文件中指定,它将自动与应用一起打包。特别是,包本身使用的资产必须在其 pubspec.yaml
中指定。
包也可以选择在其 lib/
文件夹中放置未在其 pubspec.yaml
文件中指定的资产。在这种情况下,为了打包这些图片,应用必须在其 pubspec.yaml
中指定要包含哪些。例如,一个名为 fancy_backgrounds
的包可能包含以下文件
.../lib/backgrounds/background1.png
.../lib/backgrounds/background2.png
.../lib/backgrounds/background3.png
例如,要包含第一张图片,应用的 pubspec.yaml
应在 assets
部分中指定它
flutter:
assets:
- packages/fancy_backgrounds/backgrounds/background1.png
lib/
是隐含的,因此不应包含在资产路径中。
如果你正在开发一个包,要加载包内的资产,请在包的 pubspec.yaml
中指定它
flutter:
assets:
- assets/images/
要加载包内的图片,请使用
return const AssetImage('packages/fancy_backgrounds/backgrounds/background1.png');
与底层平台共享资产
#Flutter 资产可以通过 Android 上的 AssetManager
和 iOS 上的 NSBundle
轻松地供平台代码使用。
在 Android 中加载 Flutter 资产
#在 Android 上,资产可通过 AssetManager
API 访问。例如,在 openFd
中使用的查找键,是从 PluginRegistry.Registrar
上的 lookupKeyForAsset
或 FlutterView
上的 getLookupKeyForAsset
获取的。PluginRegistry.Registrar
在开发插件时可用,而 FlutterView
将是在开发包含平台视图的应用时的选择。
例如,假设你在 pubspec.yaml 中指定了以下内容
flutter:
assets:
- icons/heart.png
这反映了你的 Flutter 应用中的以下结构。
.../pubspec.yaml
.../icons/heart.png
...etc.
要从 Java 插件代码访问 icons/heart.png
,请执行以下操作
AssetManager assetManager = registrar.context().getAssets();
String key = registrar.lookupKeyForAsset("icons/heart.png");
AssetFileDescriptor fd = assetManager.openFd(key);
在 iOS 中加载 Flutter 资产
#在 iOS 上,资产可通过 mainBundle
访问。例如,在 pathForResource:ofType:
中使用的查找键,是从 FlutterPluginRegistrar
上的 lookupKeyForAsset
或 lookupKeyForAsset:fromPackage:
,或 FlutterViewController
上的 lookupKeyForAsset:
或 lookupKeyForAsset:fromPackage:
获取的。FlutterPluginRegistrar
在开发插件时可用,而 FlutterViewController
将是在开发包含平台视图的应用时的选择。
例如,假设你有上述的 Flutter 设置。
要从 Objective-C 插件代码访问 icons/heart.png
,请执行以下操作
NSString* key = [registrar lookupKeyForAsset:@"icons/heart.png"];
NSString* path = [[NSBundle mainBundle] pathForResource:key ofType:nil];
要从 Swift 应用访问 icons/heart.png
,请执行以下操作
let key = controller.lookupKey(forAsset: "icons/heart.png")
let mainBundle = Bundle.main
let path = mainBundle.path(forResource: key, ofType: nil)
有关更完整的示例,请参阅 pub.dev 上 Flutter video_player
插件的实现。
在 Flutter 中加载 iOS 图片
#当通过将 Flutter 添加到现有 iOS 应用来集成 Flutter 时,你可能希望在 Flutter 中使用 iOS 中托管的图片。为此,请使用平台通道将图片数据作为 FlutterStandardTypedData
传递给 Dart。
平台资产
#还有其他一些直接在平台项目中处理资产的情况。下面是两种在 Flutter 框架加载和运行之前使用资产的常见情况。
更新应用图标
#更新 Flutter 应用的启动图标与更新原生 Android 或 iOS 应用的启动图标方式相同。
Android
#在你的 Flutter 项目根目录中,导航到 .../android/app/src/main/res
。各种位图资源文件夹,如 mipmap-hdpi
,已经包含名为 ic_launcher.png
的占位符图片。根据 Android 开发者指南中指示的每个屏幕密度的推荐图标大小,用你所需的资产替换它们。
iOS
#在你的 Flutter 项目根目录中,导航到 .../ios/Runner
。Assets.xcassets/AppIcon.appiconset
目录已包含占位符图片。根据 Apple 人机界面指南中指示的文件名,用适当大小的图片替换它们。保持原始文件名。
更新启动屏幕
#Flutter 还在 Flutter 框架加载时,使用原生平台机制为你的 Flutter 应用绘制过渡启动屏幕。此启动屏幕会一直显示,直到 Flutter 渲染应用的第一个帧。
Android
#要为你的 Flutter 应用添加启动屏幕(也称为“闪屏”),请导航到 .../android/app/src/main
。在 res/drawable/launch_background.xml
中,使用此 图层列表 drawable XML 来自定义你的启动屏幕外观。现有模板提供了在白色闪屏中间添加图片的代码示例(已注释)。你可以取消注释或使用其他 drawable 来实现预期效果。
有关更多详细信息,请参阅为你的 Android 应用添加闪屏。
iOS
#要将图片添加到你的“闪屏”中心,请导航到 .../ios/Runner
。在 Assets.xcassets/LaunchImage.imageset
中,放入名为 LaunchImage.png
、LaunchImage@2x.png
、LaunchImage@3x.png
的图片。如果你使用不同的文件名,请更新同一目录中的 Contents.json
文件。
你还可以通过打开 .../ios/Runner.xcworkspace
在 Xcode 中完全自定义你的启动屏幕 storyboard。导航到 Project Navigator 中的 Runner/Runner
,通过打开 Assets.xcassets
拖放图片,或者使用 LaunchScreen.storyboard
中的 Interface Builder 进行任何自定义。
有关更多详细信息,请参阅为你的 iOS 应用添加闪屏。