新增資源和圖片

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 的特殊歸檔中,以便應用在執行時讀取它們。

資源變體

建構過程支援 asset 變體:不同版本的資源可能會顯示在不同的上下文中。在 pubspec.yamlassets 部分中指定的資源路徑,會在建構過程中,查詢同級子目錄中相同名稱的任何檔案。這些檔案會與指定的資源一起被打包在資源 bundle 中。

例如,你的應用程式目錄中有以下檔案:

.../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 將被打包在你的資源 bundle 中。前者被稱為是 main asset,後者被稱為是一種變體(variant)。

如果指定的是 graphics 目錄:

flutter:
  assets:
    - graphics/

… 那麼 graphics/my_icon.pnggraphics/background.pnggraphics/dark/background.png 同時被包含。

在選擇當前裝置解析度的圖片時,Flutter 會使用資源變體;見下文。將來,這種機制可能會擴充到本地化、閱讀提示等方面。

載入 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');
}

載入圖片

Flutter 可以為當前裝置載入適合其解析度的影象。

宣告解析度相關的圖片 assets

AssetImage 可以將邏輯請求資源對映到最接近當前 裝置畫素比 的資源。為了使這種對映起作用,應該根據特定的目錄結構來儲存資源:

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

…其中 MN 是數字識別符號,對應於其中包含的影象的解析度,換句話說,它們指定不同裝置畫素比例的圖片。

主資源預設對應於 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(以邏輯畫素為單位)。

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

載入 images

載入圖片,請在 widget 的 build 方法中使用 AssetImage 類別。

例如,你的應用程式可以從上面的資源宣告中載入背景圖片:

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

使用預設的資源 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];

這有一個更完整的例項可以理解 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 的圖片

When implementing Flutter by adding it to an existing iOS app, you might have images hosted in iOS that you want to use in Flutter. To accomplish that, use the ios_platform_images plugin available on pub.dev.

平台 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

更多詳細資訊,請檢視 在 Android 應用中新增閃屏頁與啟動頁