新增資源和圖片

Flutter 應用程式包含程式碼和 assets(也為資源)。資源是被打包到應用程式安裝套件中,可以在執行時訪問的一種檔案。常見的資源型別包括靜態資料(例如 JSON 檔案),設定檔案,圖示和圖片(JPEG,WebP,GIF,動畫 WebP / GIF,PNG,BMP 和 WBMP)。

指定資源

Flutter 使用 pubspec.yaml 檔案,位於專案根目錄,來識別應用程式所需的資源。

下面舉個例子:

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

如果要包含一個目錄下的所有 assets,需要在目錄名稱的結尾加上 /

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

Asset bundling (應用打包資源)

yaml 檔案 flutter 下面的 assets 部分指定了需要包含在應用中的檔案。每個資源都透過相對於 pubspec.yaml 檔案所在位置的路徑進行標識。資源的宣告順序是無關緊要的。資源的實際目錄可以是任意資料夾(在第一個範例中是 assets,其他的是 directory

在一次建立中,Flutter 將 assets 放到 asset bundle 的特殊歸檔中,以便應用在執行時讀取它們。

載入 assets

你的應用程式可以透過 AssetBundle 物件訪問其資源。

Asset bundle 透過指定一個邏輯鍵(key),允許你讀取 string/text(loadString)和 image/binary(load)。在編譯期間,這個邏輯鍵(key)會對映在 pubspec.yaml 中指定的資源路徑。

載入文字 assets

每個 Flutter 應用程式都有一個 rootBundle 物件,可以輕鬆訪問主資源 bundle 。還可以直接使用 package:flutter/services.dart 中全域靜態的 rootBundle 來載入資源。

但是,如果獲取當前 BuildContextAssetBundle,建議使用 DefaultAssetBundle。這種方式不是使用應用程式建立的預設資源 bundle,而是讓父級 widget 在執行時替換的不同的 AssetBundle,這對於本地化或測試場景很有用。

通常,你可以從應用程式執行時的 rootBundle 中,間接使用 DefaultAssetBundle.of() 來載入資源(例如 JSON 檔案)。

在 Widget 上下文之外,或 AssetBundle 的句柄不可用時,你可以使用 rootBundle 直接載入這些 assets,例如:

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 widget 上未指定渲染影象的寬度和高度,通常會擴充套件資源來保證與主資源相同的螢幕空間量,並不是相同的物理畫素,只是解析度更高。換句話說,.../my_icon.png 是 72 px 乘 72 px,那麼 .../3.0x/my_icon.png 應該是 216 px 乘 216 px;但如果未指定寬度和高度,它們都將渲染為 72 px 乘 72 px(以邏輯畫素為單位)。

Bundling of resolution-aware image assets

你只需要在 pubspec.yamlassets 部分指定主要資源, Flutter 會自動幫你繫結其他變體。在 pubspec.yaml 中資源部分的每一項都應與實際檔案相對應,除過主資源節點。當主資源缺少某個檔案時,會按解析度從低到高的順序去選擇,也就是說 1x 中沒有的話會在 2x 中找,2x 中還沒有的話就在 3x 中找。該條目需要在 pubspec.yaml 中指定。

使用預設的資源 bundle 載入資源時,系統會自動處理解析度等。(如果你使用一些更低級別的類,如 ImageStreamImageCache,你需要注意 scale 相關的引數)。

依賴套件中的資源圖片

載入依賴 package 中的影象,必須給 AssetImage 提供 package 引數。

例如,你的應用程式依賴於一個名為 my_icons 的 package,它的目錄結構如下:

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

然後載入 image, 使用:

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

package 使用本身的 Assets 也需要加上 package 引數來獲取。

打包 assets

如果期望的資源檔案被指定在 package 的 pubspec.yaml 檔案中,它會被自動打包到應用程式中。特別是,package 本身使用的資源必須在 pubspec.yaml 中指定。

package 也可以選擇在其 lib/ 資料夾中包含未在 pubspec.yaml 檔案中宣告的資源。在這種情況下,對於要打包的圖片,應用程式必須在 pubspec.yaml 中指定包含哪些影象。例如,一個名為 fancy_backgrounds 的套件,可能包含以下檔案:

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

總而言之,要包含第一張影象,必須在 pubspec.yamlassets 部分中宣告它:

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

lib/ 是隱含的,所以它不應該包含在資源路徑中。

如果你正在開發 package,想要從 package 中載入資源,首先要在 pubspec.yaml 中定義:

flutter:
  assets:
    - assets/images/

在 package 中載入圖片,按以下方式:

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

平台共享 assets

在不同平台讀取 Flutter assets, Android 是透過 AssetManager,iOS 是 NSBundle

在 Android 中載入 Flutter 資源檔案

在 Android 平台上,assets 透過 AssetManager API 讀取。透過 PluginRegistry.RegistrarlookupKeyForAsset 方法,或者 FlutterViewgetLookupKeyForAsset 方法來獲取檔案路徑,然後 AssetManageropenFd 根據檔案路徑得到檔案描述符。開發外掛時可以使用 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 平台上,assets 資源檔案透過 mainBundle 讀取。透過 pathForResource:ofType:lookupKeyForAsset 或者 lookupKeyForAsset:fromPackage: 方法獲取檔案路徑,同樣,FlutterViewControllerlookupKeyForAsset: 或者 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)

這有一個更完整的實例可以理解 Flutter 的應用: video_player plugin

pub.dev 上的 ios_platform_images plugin 將這些邏輯封裝成方便的類別。它允許編寫:

Objective-C:

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

Swift:

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

在 Flutter 中載入 iOS 的圖片

當你在 iOS 應用程式中新增 Flutter 時,你可能希望在 Flutter 中使用 iOS 中的圖片。為了實現這一點,可以使用 pub.dev 上的 ios_platform_images 外掛。

平台 assets

某些場景可以直接在平台專案中使用 assets。以下是在 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/Runner 路徑。該目錄中 Assets.xcassets/AppIcon.appiconset已經包含佔位符圖片,只需將它們替換為適當大小的圖片,並且根據 iOS 開發指南,檔案名稱保持不變。

iOS icon location

更新啟動圖

Launch screen

在 Flutter 框架載入時,Flutter 會使用原生平台機制繪製啟動頁。此啟動頁將持續到 Flutter 渲染應用程式的第一幀。

Android

將啟動螢幕「splash screen」新增到你的 Flutter 應用程式,請導向至 .../android/app/src/main 路徑。在 res/drawable/launch_background.xml 檔案中,透過使用 圖層清單 XML 來實現自定義啟動頁。現有樣板提供了一個範例,用於將圖片新增到白色啟動頁的中間(註解程式碼中)。你也可以取消註解使用 可繪製物件資源 來實現預期效果。

更多詳細訊息,請檢視 在 Android 應用中新增螢幕閃爍頁與啟動頁

iOS

將圖片新增到啟動螢幕「splash screen」的中心,請導向至 .../ios/Runner 路徑。在 Assets.xcassets/LaunchImage.imageset ,拖入圖片,並命名為 LaunchImage.pngLaunchImage@2x.pngLaunchImage@3x.png。如果你使用不同的檔案名,那你還必須更新同一目錄中的 Contents.json 檔案中對應的名稱。

你也可以透過開啟 .../ios/Runner.xcworkspace ,完全自定義 storyboard。在 Project Navigator 中導向到 Runner/Runner ,然後開啟 Assets.xcassets 拖入圖片,或者在 LaunchScreen.storyboard 中使用 Interface Builder 進行自定義。

Adding launch icons in Xcode

更多詳細訊息,請檢視 在 iOS 應用中新增螢幕閃爍頁與啟動頁