Flutter之添加资源和图片

808 阅读9分钟

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/

1.1、资源捆绑

flutter部分的资源部分指定应包含在应用程序的文件。每个资源都由资源文件所在的显示路径(相对于pubspec.yaml文件)标识。声明资源的顺序无关紧要。使用的实际目录名称(第一个示例中的资源或上面示例中的目录)无关紧要。

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

1.2、资源变体

构建过程支持资源变体的概念:可能在不同上下文中显示的资源的不同版本。当在pubspec.yaml的资源部分指定资源的路径时,构建过程会在相邻的目录中查找任何具有相同名称的文件。然后,此类文件与指定资源一起包含在资源包中。

例如,如果您的应用程序目录中有以下文件:

.../pubspec.yaml
.../graphics/my_icon.png
.../graphics/background.png
.../graphics/dark/background.png
...etc.

您的pubspec.yaml文件包含以下内容:

flutter:
  assets:
    - graphics/background.png

然后graphics/background.pnggraphics/dark/background.png包含在您的资源包中。前者被认为是主要资产,而后者被认为是变体。

另一方面,如果制定了图形目录:

flutter:
  assets:
    - graphics/

然后还包含graphics/my_icon.pnggraphics/background.pnggraphics/dark/background.png文件。

Flutter在选择适合分辨率的图像时使用资源变体。将来,此机制可能会扩展到包括针对不同语言环境或区域、阅读方向等变体。

二、加载资源

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

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

2.1、加载文本资源

每个Flutter应用程序都由一个rootBundle对象,可以轻松访问主资源包。可以使用pac的kage: flutter/service.dart中的rootBundle全局静态直接加载资源。

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

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

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

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

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

2.2、加载图片

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

2.2.1、声明分辨率感知图像资源

AssetImage了解如何将逻辑请求的资源映射到与当前设备像素比最匹配的资源。为了使此映射起作用,资源应根据特定的目录结构进行排列:

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

其中M和N是数字标识符,对应于其中包含的图像的标称分辨率。换句话说,它们指定了,我们指定了图像预期的设备像素比。

假定主要资源对应于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(以逻辑像素为单位)。

pubsspec.yaml的资源部分中的每个条目都对应于一个真实文件,但住资源条目除外。如果主要资源条目与真实文件不对应,则分辨率最低的资源将用作设备像素比低于该分辨率的设备的后备。但是,该条目仍应包含在pubspec.yaml清单中。

2.2.2、加载图片

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

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

return const Image(image: AssetImage('graphics/backgroud.png'));

任何使用默认资源包的东西在加载图像时都会继承分辨率感知。(如果您使用一些较低级别的类,如ImageStreamImageCache,您还会注意到与比例相关的参数。)

注意:设备像素比率取决于`MediaQueryData.size`,这需要将`MaterialApp``CupertinoApp`作为您的`AssetImagee`的祖先。

2.3、包依赖项中的资源图像

要从包依赖加载图像,必须向AssetImage提供包参数。

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

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

加载图片使用:

return const AssetImabe('icons/hheart.png', package: 'my_icons');

包本身使用的资源也应该使用上面包的参数来获取。

2.3.1、打包资源的捆绑

如果在包的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应在资源部分指定它:

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

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

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

flutter:
  assets:
    - assets/images/

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

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

三、与底层平台共享资源

使用Android上的AssetManager和iOS上的NSBundle, Flutter资源可轻松用于平台代码。

3.1、在Android中加载Flutter资源

在Android身上,资源可通过AssetManager API获得。例如openFd中使用的查找键是从PluginRegistry.Registrar上的lookupKeyForAssetFlutterView上的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);

3.2、在iOS中加载Flutter资源

在iOS上,资源可通过mainBundle获得。例如pathForResource:ofType:中使用的查找键是从FlutterPluginRegistrar上的lookupKeyForAssetlookupKeyForAsset: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];

video_player有关更完整的示例,请参阅 pub.dev 上 Flutter插件的实现。

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

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

Swift

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

3.3、在Flutter中加载iOS图片

通过将 Flutter 添加到现有的 iOS 应用程序来实现 Flutter 时,您可能会在 iOS 中托管您想要在 Flutter 中使用的图像。为此,请使用ios_platform_imagespub.dev 上可用的插件。

四、平台资源

还有其他场合可以直接使用平台项目中的资源。下面是在Flutter框架加载和运行之前使用资源的两种情况。

4.1、更新应用程序图标

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

image.png

### 4.1.1、Android 在您的FLutter项目的根目录中,导航到`.../android/app/src/main/res`各种位图资源文件夹,例如`mipmap-hdpi`已经包含名为`ic_launcher.png`.按照[Android 开发人员指南](https://developer.android.com/training/multiscreen/screendensities)中的指示,根据屏幕密度推荐的图标大小,将它们替换为您想要的资源。

image.png

**注意:**  如果重命名文件,还必须更新 的标签 属性`.png`中的相应名称。`AndroidManifest.xml``<application>``android:icon`

4.1.2、iOS

在您的FLutter项目的根目录中,导航到.../ios/Runner,该Assets.cassets/AppIcon.appiconset目录已包含占位符图像。按照 Apple Human Interface Guidelines的规定,将它们替换为文件名所指示的适当大小的图像。保留原始文件名。

image.png

## 4.2、更新启动屏幕

image.png

Flutter还使用原生平台机制在Flutter框架加载时为您的Flutter应用程序绘制过渡启动屏幕。此启动屏幕一直存在,直到Flutter呈现您的应用程序的第一帧。

**注意:**  这意味着如果您不调用应用程序的[`runApp()`](https://api.flutter.dev/flutter/widgets/runApp.html)功能 `main()`(或者更具体地说,如果您不响应[`window.render()`](https://api.flutter.dev/flutter/dart-ui/Window/render.html)) [`window.onDrawFrame`](https://api.flutter.dev/flutter/dart-ui/Window/onDrawFrame.html),启动屏幕将永远存在。

4.2.1、Android

要将启动屏幕添加到您的Flutter应用程序,请导航至.../android/app/src/main,在res/drawable/launcher_background.xml,使用此图层列表可绘制XML自定义启动屏幕的外观。现有模版提供了在注释代码中将添加到白色闪屏中间的示例。您可以取消注释或使用其他可 绘制对象来达到预期效果。

有关详细信息,请参阅 向您的移动应用程序添加启动画面

4.2.2、iOS

要将图像添加到”启动画面“的中心,请导航至.../ios/Runner。在Assets.xcassets/LauncherImage.imageset,,放入名为LaunchImage.pngLaunchImage@2x.png,的图像LaunchImage@3x.png。如果您使用不同的文件名,请更新Contents.json同一目录中的文件。

您还可以在 Xcode 中完全自定义启动屏幕故事板,方法是打开.../ios/Runner.xcworkspace. 导航到Project Navigator 并通过打开或使用 Interface Builder 进行任何自定义来 Runner/Runner放入图像。Assets.xcassets``LaunchScreen.storyboard

image.png

有关详细信息,请参阅 [向您的移动应用程序添加启动画面](https://docs.flutter.dev/development/ui/advanced/splash-screen)。