Skip to main content

添加资源和图片

Flutter 应用可以包含代码和 资源 (有时称为资源)。资源是与您的应用捆绑在一起并在部署时可访问的文件。常见的资源类型包括静态数据(例如,JSON 文件)、配置文件、图标和图像(JPEG、WebP、GIF、动画 WebP/GIF、PNG、BMP 和 WBMP)。

指定资源

#

Flutter 使用位于项目根目录的 pubspec.yaml 文件来识别应用所需的资源。

这是一个示例:

yaml
flutter:
  assets:
    - assets/my_icon.png
    - assets/background.png

要包含目录下的所有资源,请在末尾使用 / 字符指定目录名:

yaml
flutter:
  assets:
    - directory/
    - directory/subdirectory/

资源捆绑

#

flutter 部分的 assets 子部分指定应与应用一起包含的文件。每个资源都由一个显式路径(相对于 pubspec.yaml 文件)标识,该路径指示资源文件的位置。声明资源的顺序无关紧要。使用的实际目录名(在第一个示例中为 assets,在上述示例中为 directory)无关紧要。

在构建过程中,Flutter 将资源放入一个称为 资源包 的特殊存档中,应用在运行时从中读取。

构建时资源文件的自动转换

#

Flutter 支持在构建应用时使用 Dart 包来转换资源文件。为此,请在您的 pubspec 文件中指定资源文件和转换器包。要了解如何执行此操作以及编写您自己的资源转换包,请参阅构建时转换资源

基于应用版本的条件资源捆绑

#

如果您的项目使用了版本功能,您可以配置仅在应用的某些版本中捆绑各个资源。有关更多信息,请查看[基于版本的条件资源捆绑]。

加载资源

#

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

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

加载文本资源

#

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

但是,建议使用 DefaultAssetBundle 获取当前 BuildContextAssetBundle,而不是使用与应用一起构建的默认资源包;这种方法使父小部件能够在运行时替换不同的 AssetBundle,这对于本地化或测试场景非常有用。

通常,您将使用 DefaultAssetBundle.of() 间接加载资源(例如 JSON 文件),来自应用的运行时 rootBundle

Widget 上下文之外,或当 AssetBundle 的句柄不可用时,您可以使用 rootBundle 直接加载此类资源。例如:

dart
import 'package:flutter/services.dart' show rootBundle;

Future<String> loadAsset() async {
  return await rootBundle.loadString('assets/config.json');
}

加载图像

#

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

例如,您的应用可以从前面示例中的资源声明加载背景图像:

dart
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 基线)
.../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,您还会注意到与缩放相关的参数。)

包依赖项中的资源图像

#

要从 依赖项加载图像,必须将 package 参数提供给 AssetImage

例如,假设您的应用程序依赖于名为 my_icons 的包,其具有以下目录结构:

.../pubspec.yaml
.../icons/heart.png
.../icons/1.5x/heart.png
.../icons/2.0x/heart.png
...etc.

要加载图像,请使用:

dart
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 部分中指定它:

yaml
flutter:
  assets:
    - packages/fancy_backgrounds/backgrounds/background1.png

lib/ 是隐含的,因此不应将其包含在资源路径中。

如果您正在开发一个包,要加载包中的资源,请在包的 pubspec.yaml 中指定它:

yaml
flutter:
  assets:
    - assets/images/

要加载包中的图像,请使用:

dart
return const AssetImage('packages/fancy_backgrounds/backgrounds/background1.png');

与底层平台共享资源

#

Flutter 资源可通过 Android 上的 AssetManager 和 iOS 上的 NSBundle 轻松访问平台代码。

在 Android 中加载 Flutter 资源

#

在 Android 上,可以通过 AssetManager API 访问资源。例如,在 openFd 中使用的查找键是从 PluginRegistry.Registrar 上的 lookupKeyForAssetFlutterView 上的 getLookupKeyForAsset 获取的。在开发插件时可以使用 PluginRegistry.Registrar,而在开发包含平台视图的应用时,FlutterView 将是选择。

例如,假设您在 pubspec.yaml 中指定了以下内容:

yaml
flutter:
  assets:
    - icons/heart.png

这反映了 Flutter 应用中的以下结构。

.../pubspec.yaml
.../icons/heart.png
...etc.

要从您的 Java 插件代码访问 icons/heart.png,请执行以下操作:

java
AssetManager assetManager = registrar.context().getAssets();
String key = registrar.lookupKeyForAsset("icons/heart.png");
AssetFileDescriptor fd = assetManager.openFd(key);

在 iOS 中加载 Flutter 资源

#

在 iOS 上,可以通过 mainBundle 访问资源。例如,在 pathForResource:ofType: 中使用的查找键是从 lookupKeyForAssetlookupKeyForAsset:fromPackage: 获取的。 在 FlutterPluginRegistrar 上,或在 FlutterViewController 上使用 lookupKeyForAsset:lookupKeyForAsset:fromPackage:。在开发插件时可以使用 FlutterPluginRegistrar,而在开发包含平台视图的应用时,FlutterViewController 将是选择。

例如,假设您有上面提到的 Flutter 设置。

要从您的 Objective-C 插件代码访问 icons/heart.png,您可以执行以下操作:

objc
NSString* key = [registrar lookupKeyForAsset:@"icons/heart.png"];
NSString* path = [[NSBundle mainBundle] pathForResource:key ofType:nil];

要从您的 Swift 应用访问 icons/heart.png,您可以执行以下操作:

swift
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:

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

Swift:

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

在 Flutter 中加载 iOS 图片

#

当通过将其添加到现有 iOS 应用中 来实现 Flutter 时,您可能在 iOS 中托管了一些图像,您希望在 Flutter 中使用这些图像。为此,请使用 pub.dev 上提供的 ios_platform_images 插件。

平台资源

#

在平台项目中直接处理资源还有其他情况。以下是两种常见情况,在这些情况下,资源在 Flutter 框架加载并运行之前使用。

更新应用图标

#

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

启动图标

Android

#

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

Android 图标位置

iOS

#

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

iOS 图标位置

更新启动画面

#

启动画面

Flutter 还使用原生平台机制在 Flutter 框架加载时为您的 Flutter 应用绘制过渡启动画面。此启动画面会持续存在,直到 Flutter 渲染应用程序的第一帧。

Android

#

要向您的 Flutter 应用程序添加启动画面(也称为“启动画面”),请导航到 .../android/app/src/main。在 res/drawable/launch_background.xml 中,使用此图层列表可绘制对象 XML 来自定义启动画面的外观。现有的模板提供了一个将图像添加到白色启动画面中间的示例(在注释代码中)。您可以取消注释它或使用其他可绘制对象 来实现预期的效果。

有关更多详细信息,请参阅向您的 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 中的界面构建器进行任何自定义。

在 Xcode 中添加启动图标

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