react-native
中使用Image
組件來顯示圖片,表面上和html
的img
標籤大同小異,可是其source
屬性包含的邏輯缺複雜的多,同時也和bundle
運行的方式也有關係。html
本篇文章將重點講解下Image
中圖片解析邏輯,以及如何自定義圖片解析邏輯。react
react-native bundle --entry-file index.js --bundle-output ./bundle/ios/main.jsbundle --platform ios --assets-dest ./bundle/ios --dev false
react-native bundle --entry-file index.js --bundle-output ./bundle/android/index.bundle --platform android --assets-dest ./bundle/android --dev false
複製代碼
首先看下iOS
和android
打包結果:android
iOS
會按照項目結構輸出圖片資源到咱們制定的目錄assets
下。ios
android
中,drawable-mdpi
、drawable-xhdpi
、drawable-xxhdpi
等存放不一樣分辨率屏幕下的圖片,文件名的組成是目錄和圖片名稱經過_
拼接。react-native
代碼位於react-native/Libraries/Image/resolveAssetSource
服務器
resolveAssetSource.js
最終會export
如下內容:app
module.exports = resolveAssetSource;
module.exports.pickScale = AssetSourceResolver.pickScale;
module.exports.setCustomSourceTransformer = setCustomSourceTransformer;
複製代碼
這裏的重點是resolveAssetSource
,它會處理Image
的source
,並返回圖片地址。函數
建立了AssetSourceResolver
,並傳入getDevServerURL()
、getScriptURL()
、asset
。工具
若是存在自定義處理函數_customSourceTransformer
,就返回它的執行結果。它的設置就是經過setCustomSourceTransformer
來完成的。ui
不然就調用resolver.defaultAsset
,使用默認的邏輯處理圖片。
/** * `source` is either a number (opaque type returned by require('./foo.png')) * or an `ImageSource` like { uri: '<http location || file path>' } */
function resolveAssetSource(source: any): ?ResolvedAssetSource {
if (typeof source === 'object') {
return source;
}
const asset = AssetRegistry.getAssetByID(source);
if (!asset) {
return null;
}
const resolver = new AssetSourceResolver(
getDevServerURL(),
getScriptURL(),
asset,
);
if (_customSourceTransformer) {
return _customSourceTransformer(resolver);
}
return resolver.defaultAsset();
}
複製代碼
接下來看AssetSourceResolver.js
的代碼。
咱們前文初始化AssetSourceResolver
,設置了三個參數:
bundle
所在位置裏面包含了最終返回圖片的邏輯:defaultAsset
,咱們分析以後能夠獲得:
server
經過以下代碼拼接圖片地址,這裏使用serverUrl
要求bundle
文件和圖片在同級目錄而且在域名下,中間不能有二級目錄。
this.fromSource(
this.serverUrl +
getScaledAssetPath(this.asset) +
'?platform=' +
Platform.OS +
'&hash=' +
this.asset.hash,
);
複製代碼
解決方案是經過
setCustomSourceTransformer
替換serverUrl
,改成jsbundleUrl
。
app
這裏不一樣平臺的處理方式又不同。
iOS
從資源中加載圖片
android
分爲兩種:資源和文件系統(file://)
class AssetSourceResolver {
serverUrl: ?string;
// where the jsbundle is being run from
jsbundleUrl: ?string;
// the asset to resolve
asset: PackagerAsset;
constructor(serverUrl: ?string, jsbundleUrl: ?string, asset: PackagerAsset) {
this.serverUrl = serverUrl;
this.jsbundleUrl = jsbundleUrl;
this.asset = asset;
}
...
defaultAsset(): ResolvedAssetSource {
if (this.isLoadedFromServer()) {
return this.assetServerURL();
}
if (Platform.OS === 'android') {
return this.isLoadedFromFileSystem()
? this.drawableFolderInBundle()
: this.resourceIdentifierWithoutScale();
} else {
return this.scaledAssetURLNearBundle();
}
}
複製代碼
咱們瞭解Image
組件的圖片邏輯以後,就能夠按需調整了,經過調用setCustomSourceTransformer
傳入自定義函數來控制最終圖片的訪問地址。
我在項目中的處理是bundle
部署在服務器上,這種方式會有兩個問題:
drawable-x
目錄上面的問題都是圖片沒法顯示,不知道看到文章的你是否也想到了解決辦法?
本文同步發表於做者博客: React Native 圖片資源那些事