Flutter的資源類型
Flutter可以添加代碼以及assets
到APP中。而每個(gè)Asset都是被打包在發(fā)布的APP中的抛蚁,并且在APP運(yùn)行時(shí)可以訪問(wèn)這些資源舅踪。
通用的Asset類型包括:
- JSON文件
- 配置文件
- 圖標(biāo)
- 位圖(JPEG、Webp绕沈、Gif、Animated Gif/Webp帮寻、PNG)
指定Asset
Flutter使用項(xiàng)目根目錄下的pubspec.yaml
文件來(lái)指定APP所需要的資源乍狐。
- 單個(gè)文件指定:
flutter:
assets:
- assets/my_icon.png
- assets/background.png
- 文件夾指定:
通過(guò)指定目錄名+/
字符即可,只有在該目錄下的所有文件可以被包括固逗,如果該目錄還有子目錄的話浅蚪,則需要添加一個(gè)新的Entry。
flutter:
assets:
- assets/
- assets/image/
Asset Variants
構(gòu)建系統(tǒng)支持Asset Variants
的概念:
在不同的環(huán)境下烫罩,需要顯示不同版本的資源惜傲。
例如,日夜間模式的資源贝攒,資源名相同盗誊,但是環(huán)境不同。
當(dāng)一個(gè)資源的路徑在pubspec.yaml
文件的assets
Section中指定的時(shí)候隘弊,構(gòu)建系統(tǒng)就會(huì)在相鄰的子目錄中查找相同的名稱的資源文件哈踱。而查找到的這些文件也會(huì)被打到Asset Bundle中。
例如:有一個(gè)background.png
文件梨熙,在日夜間都需要使用开镣,graphics
中存放日間資源,而dark
中存放夜間資源咽扇。
.../pubspec.yaml
.../graphics/my_icon.png
.../graphics/background.png
.../graphics/dark/background.png
...etc.
而在pubspec.yaml
文件中邪财,將background.png
添加到assets
的Section中。
flutter:
assets:
- graphics/background.png
最終质欲,在打包的時(shí)候會(huì)把.../graphics/background.png
和.../graphics/dark/background.png
都打到Bundle中树埠。而前一個(gè)被認(rèn)為是Main Bundle
,而后一個(gè)則認(rèn)為是Variant Bundle
把敞。
而如果使用:
flutter:
assets:
- graphics/
則myicon.png
弥奸,background.png
,/dark/background.png
也都會(huì)打到Bundle中奋早。
Flutter目前使用Asset Variant來(lái)解決圖片適配的問(wèn)題盛霎,而未來(lái)這種機(jī)制也會(huì)應(yīng)用在不同的語(yǔ)言等其他地方。
加載Assets
APP可以通過(guò)AssetBundle
對(duì)象來(lái)訪問(wèn)資源耽装。
- 加載String/Text:通過(guò)
loadString
方法 - 加載圖片/二進(jìn)制文件:通過(guò)
load
方法
而在Build的階段愤炸,邏輯Key會(huì)根據(jù)pubspec.yaml
文件中的路徑來(lái)進(jìn)行映射。
每個(gè)Flutter App都有一個(gè)rootBundle
對(duì)象來(lái)方便的訪問(wèn)主資源Bundle掉奄」娓觯可以通過(guò)package:flutter/services.dard
中的全局靜態(tài)變量rootBundle
來(lái)直接訪問(wèn)資源凤薛。不過(guò)還是推薦使用當(dāng)前的BuildContext
來(lái)獲取DefaultAssetBundle
,通過(guò)調(diào)用DefaultAssetBundle.of(context)
來(lái)獲取诞仓。
而當(dāng)沒(méi)有Context
的Widget缤苫,則需要通過(guò)rootBundle
來(lái)獲取。
import 'dart:async' show Future;
import 'package:flutter/services.dart' show rootBundle;
Future<String> loadAsset() async {
return await rootBundle.loadString('assets/config.json');
}
圖片加載的適配
Flutter會(huì)根據(jù)當(dāng)前設(shè)備的設(shè)備像素比(device Pixel Ratio)來(lái)選擇圖片墅拭。
AssetImage
知道如何映射到最相近的設(shè)備像素比的圖片活玲,為了讓Mapping能夠更好的工作,Assets應(yīng)該有這種結(jié)構(gòu):
.../my_icon.png
.../2.0x/my_icon.png
.../3.0x/my_icon.png
默認(rèn)主資源Bundle中是1.0x的圖片谍婉。
例如舒憾,當(dāng)前設(shè)備的設(shè)備像素比是1.8,則會(huì)選擇
/2.0x/my_icon.png
穗熬。如果是2.7時(shí)镀迂,則會(huì)選擇/3.0x/my_icon.png
。
如果Image
控件的寬高都沒(méi)有指定的話唤蔗,通常的解決方案是進(jìn)行資源壓縮探遵,然后和主資源Bundle中的圖占據(jù)相同的像素空間。
例如措译,1.0x的my_icon.png是72px * 72px别凤,而3.0x的my_icon.png是216px * 216px,但是它需要繪制到72px * 72px的Image控件上领虹,如果這個(gè)控件的寬高沒(méi)有指定的話规哪。
加載圖片
在Widget的build
函數(shù)中使用AssetImage
類來(lái)加載圖片。
Widget build(BuildContext context) {
// ...
return DecoratedBox(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('graphics/background.png'),
// ...
),
// ...
),
);
// ...
}
與平臺(tái)共享資源
Flutter的Asset資源也可以與Android/Ios共享塌衰。例如诉稍,flutter中有heart.png
這張圖
flutter:
assets:
- icons/heart.png
Android:
Android上通過(guò)AssetManager
來(lái)獲取。
- 通過(guò)
PluginRegistry.Registrar
的lookupKeyForAsset
來(lái)獲取文件路徑 - 通過(guò)
FlutterView
的getLookupKeyForAsset
來(lái)獲取文件路徑 - 通過(guò)
AssetManager
的openFd
來(lái)得到文件描述符
AssetManager assetManager = registrar.context().getAssets();
String key = registrar.lookupKeyForAsset("icons/heart.png");
AssetFileDescriptor fd = assetManager.openFd(key);
IOS:
IOS上通過(guò)NSBundle
來(lái)獲取最疆。
- 通過(guò)
FlutterPluginRegistrar
的lookupKeyForAsset
來(lái)獲取文件路徑 - 通過(guò)
FlutterViewController.FlutterPluginRegistrar
同樣也可以獲取文件路徑 - 通過(guò)
NSBundle
的pathForResource
來(lái)獲取文件路徑
NSString* key = [registrar lookupKeyForAsset:@"icons/heart.png"];
NSString* path = [[NSBundle mainBundle] pathForResource:key ofType:nil];