Skip to content

Latest commit

 

History

History
253 lines (171 loc) · 8.27 KB

08. Flutter用户交互 - 资源和图片.md

File metadata and controls

253 lines (171 loc) · 8.27 KB

Adding assets and images

Flutter app 包含code和assets(资源). asset文件夹和app一起打包部署, 在运行过程中可以被访问. 通常类型的asset包含静态数据(如JSON文件), 配置文件, 图标, 图片(JPEG, WebP, GIF, animated WebP/GIF, PNG, BMP, and WBMP)

指定 assets Specifying assets

使用位于根路径的pubspec.yaml文件, 来识别app所需的asset.

例如:

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

如果想要包含assets中文件夹下的所有资源, 指定文件夹名字 + /

flutter:
  assets:
    - assets/

注意, 只有直接包含在当前文件夹下的文件才会被包含. 如果想添加子文件夹下面的文件, 给每个文件夹创建一个入口

Asset bundling

assets中指定了需要包含到app的文件. 每个asset有一个明确的文件路径(相对pubspec.yaml的路径).

编译阶段, Flutter将assets归档成一个特殊的文件, 叫asset bundle. app在运行时, 可以读取它的内容.

Asset variants

编译操作支持asset variants概念: 不同版本的asset可能会显示不同内容. 当pubspec.yaml的assets区中指定了某个asset的路径, 编译过程中会查找有同样名字的文件或者文件夹. 这些文件与指定的asset一起, 被包含到asset bundle中.

例如, 有以下文件在app的文件夹中

  .../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 会被包含到asset bundle中. 前一个叫main asset, 后一个叫 variant

另外, 如果指定的是graphics文件夹:

flutter:
  assets:
    - graphics/

graphics/my_icon.png, graphics/background.pnggraphics/dark/background.png 会被包含.

Flutter使用asset variants来选择合适的图片资源. 未来该机制可能会拓展.

Loading assets

使用AssetBundle对象来访问app中的assets

根据给定的逻辑key, asset bundle有两个方法让你可以加载字符串/文本资源(loadString)或 图片/二进制资源(load). 在编译过程中, key和pubspec.yaml指定的资源路径会进行映射.

加载文本资源 Loading text assets

每个Flutter app有一个rootBundle对象, 来更好地访问main asset bundle. 使用rootBundle(package:flutter/services.dart)直接加载资源

然而, 推荐使用DefaultAssetBundle来获取当前BuildContext的AssetBundle. 而不是使用app默认的asset bundle, 这个方法允许父widget在运行过程中替换不同的AssetBundle, 对本地化或者测试环境非常有用.

通常情况下, 使用DefaultAssetBundle.of()来间接地从rootBundle中加载某个asset, 如JSON文件.

Widget内容之外, 或者无法使用AssetBundle的情况, 可以使用rootBundle直接接在assets, 如

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

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

Loading images

Flutter可以根据当前设备的像素比加载合适分辨率的图片

Declaring resolution-aware image assets

AssetImage知道, 如何匹配与当前设备像素比最为接近的资源. 为了匹配可以成功, assets需要按照特定的文件结构进行安排.

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

M and N 是数字标识, 符合图片包含的像素分辨率. 换句话说, 他们指明了图片用在哪个像素比的设备上.

假设main asset符合1.0像素. 如,

  .../my_icon.png
  .../2.0x/my_icon.png
  .../3.0x/my_icon.png

在1.8像素比的设备中, 会选择.../2.0x/my_icon.png的资源. 在2.7像素比的设备中, 会选择.../3.0x/my_icon.png资源.

如果Image widget中所渲染的图片没有指定宽高, 像素分辨率会按比例显示资源, 它有更高的像素, 但会和main asset占用同样的屏幕空间. 也就是, 如果.../my_icon.png是72px x 72px, 则.../3.0x/my_icon.png 是 216px by 216px; 但是如果它们的宽高没有指定, 都会渲染为72px x 72px(逻辑像素)

pubspec.yaml中asset区中的每个入口都需要符合一个真实的文件, main asset的入口除外. 如果main asset入口没有符合一个真实文件, 会使用最低像素的asset在低于该像素比的设备上使用. 然而, 它的入口仍需要在pubspec.yaml中体现.

Loading images

在widget的build方法中, 使用AssetImage来加载图片.

如, 加载背景图

Widget build(BuildContext context) {
  // ...
  return DecoratedBox(
    decoration: BoxDecoration(
      image: DecorationImage(
        image: AssetImage('graphics/background.png'),
        // ...
      ),
      // ...
    ),
  );
  // ...
}

使用默认asset bundle加载图片时会继承分辨率识别.(如果使用更低等级的类, 如 ImageStream 或 ImageCache, 你会发现参数与比例相关联)

Asset images in package dependencies

加载 package依赖中的图片. 需提供一个package参数给AssetImage.

如, 假设你的app依赖一个my_icons package, 文件夹结构如下.

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

为了加载图片, 使用

AssetImage('icons/heart.png', package: 'my_icons')

package自身使用到资源时, 也需要传入如上参数.

Bundling of package assets

目标asset, 如果在pubspec.yaml文件中指定了packaget, 该资源会自动打包. 特别是package中自身使用到的assets必须要在pubspec.yaml中指明.

一个package也可以选择将, assets保存在lib/文件夹中, 而不是指定在 pubspec.yaml文件中. 这种情况下, app需在pubspec.yaml中指明哪几个需要被包含, 来打包那些图片.

例如, 名为fancy_backgrounds的package有以下文件

  .../lib/backgrounds/background1.png
  .../lib/backgrounds/background2.png
  .../lib/backgrounds/background3.png

为了包含, 假设是第一个图片, 需要在app的pubspec.yaml中的assets区域指明

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

lib/是隐式的, 因此不需要包含在asset路径中

分享资源给底层平台 Sharing assets with the underlying platform

Flutter assets可以使用安卓的AssetManager和iOS的NSBundle访问

Android

On Android the assets are available via the AssetManager API. The lookup key used in for instance openFd is obtained from lookupKeyForAsset on PluginRegistry.Registrar or getLookupKeyForAsset on FlutterView. PluginRegistry.Registrar is available when developing a plugin while FlutterView would be the choice when developing an app including a platform view.

As an example, suppose you have specified this in your pubspec.yaml

flutter:
  assets:
    - icons/heart.png

reflecting the following structure in your Flutter app.

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

To access icons/heart.png from your Java plugin code you would do;

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

iOS

On iOS the assets are available via the mainBundle. The lookup key used in for instance pathForResource:ofType: is obtained from lookupKeyForAsset or lookupKeyForAsset:fromPackage: on FlutterPluginRegistrar or lookupKeyForAsset: or lookupKeyForAsset:fromPackage: on FlutterViewController. FlutterPluginRegistrar is available when developing a plugin while FlutterViewController would be the choice when developing an app including a platform view.

As an example, suppose you have the Flutter setting from above.

To access icons/heart.png from your Objective-C plugin code you would do;

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

For a more complete example see the implementation of the Flutter video_player plugin.

Platform assets

App图标和启动页 Doc

Updating the app icon

Android
iOS

Updating the launch screen

Android
iOS