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 圖片資源那些事