添加资源和图像

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 将资产放入一个称为资产包的特殊存档中,应用在运行时从中读取。

加载资产

您的应用可以通过 AssetBundle 对象访问其资产。

资产包上的两个主要方法允许您加载字符串/文本资产 (loadString()) 或图像/二进制资产 (load()) 出包,给定一个逻辑键。逻辑键映射到构建时 pubspec.yaml 文件中指定的资产路径。

加载文本资产

每个 Flutter 应用都有一个 rootBundle 对象,用于轻松访问主资产包。可以使用 package:flutter/services.dart 中的 rootBundle 全局静态直接加载资产。

但是,建议使用 DefaultAssetBundle 为当前 BuildContext 获取 AssetBundle,而不是与应用一起构建的默认资产包;此方法使父小组件能够在运行时替换不同的 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');
}

加载图像

要加载图像,请在小部件的 build() 方法中使用 AssetImage 类。

例如,您的应用可以从上一个示例中的资产声明中加载背景图像

return const Image(image: AssetImage('assets/background.png'));

分辨率感知图像资产

Flutter 可以为当前 设备像素比率 加载分辨率合适的图像。

AssetImage 会将一个逻辑请求的资产映射到最接近当前 设备像素比率 的资产。

为了使此映射起作用,资产应按照特定的目录结构进行排列

.../image.png
.../Mx/image.png
.../Nx/image.png
...etc.

其中,MN 是与其中包含的图像的名义分辨率相对应的数字标识符。换句话说,它们指定了图像的预期设备像素比率。

在此示例中,image.png 被视为主资产,而 Mx/image.pngNx/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 小组件上指定呈现图像的宽度和高度,则使用标称分辨率缩放资产,使其占据与主资产相同数量的屏幕空间,只是分辨率更高。也就是说,如果 .../my_icon.png 为 72px x 72px,则 .../3.0x/my_icon.png 应为 216px x 216px;但如果未指定宽度和高度,它们都呈现为 72px x 72px(以逻辑像素为单位)。

分辨率感知图像资产的捆绑

您只需在 pubspec.yamlassets 部分中指定主资产或其父目录。Flutter 会为您捆绑变体。除了主资产条目外,每个条目都应对应一个真实文件。如果主资产条目不对应真实文件,则将最低分辨率的资产用作设备像素比率低于该分辨率的设备的备用资产。但是,该条目仍应包含在 pubspec.yaml 清单中。

使用默认资产包的任何内容在加载图像时都会继承分辨率感知。(如果您使用某些较低级别的类,如 ImageStreamImageCache,您还会注意到与缩放相关的参数。)

软件包依赖项中的资产图像

要从 依赖项加载图像,必须向 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.RegistrarFlutterView 上的 lookupKeyForAsset 中获取。开发插件时可以使用 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 获取资源。例如,在 FlutterPluginRegistrarFlutterViewController 上的 lookupKeyForAssetlookupKeyForAsset: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 插件

pub.dev 上的 ios_platform_images 插件将此逻辑包装在一个便捷的类别中。您可以按如下方式获取图像

Objective-C

[UIImage flutterImageWithName:@"icons/heart.png"];

Swift

UIImage.flutterImageNamed("icons/heart.png")

在 Flutter 中加载 iOS 图像

通过 将 Flutter 添加到现有 iOS 应用 来实现 Flutter 时,您可能拥有托管在 iOS 中并希望在 Flutter 中使用的图像。要实现此目的,请使用 pub.dev 上提供的 ios_platform_images 插件。

平台资产

还有其他场合需要直接在平台项目中使用资产。以下是两个常见案例,其中在加载并运行 Flutter 框架之前使用资产。

更新应用图标

更新 Flutter 应用程序的启动图标与在原生 Android 或 iOS 应用程序中更新启动图标的方式相同。

Launch icon

Android

在 Flutter 项目的根目录中,导航至 .../android/app/src/main/res。各种位图资源文件夹(例如 mipmap-hdpi)已包含名为 ic_launcher.png 的占位符图像。根据 Android 开发者指南 指示的每个屏幕密度的建议图标大小,用您所需的资产替换它们。

Android icon location

iOS

在 Flutter 项目的根目录中,导航至 .../ios/RunnerAssets.xcassets/AppIcon.appiconset 目录已包含占位符图像。根据 Apple 人机界面指南 中由文件名指示的适当大小的图像替换它们。保留原始文件名。

iOS icon location

更新启动屏幕

Launch screen

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[email protected][email protected] 的图像。如果你使用不同的文件名,请更新同一目录中的 Contents.json 文件。

你还可以通过打开 .../ios/Runner.xcworkspace 在 Xcode 中完全自定义启动屏幕情节提要。在项目导航器中导航到 Runner/Runner,并通过打开 Assets.xcassets 放入图像,或使用 LaunchScreen.storyboard 中的界面构建器进行任何自定义。

Adding launch icons in Xcode

有关更多详细信息,请参阅向 iOS 应用添加启动画面