靜態(tài)圖片資源
從0.14版本開始,React Native提供了一個統(tǒng)一的方式來管理iOS和Android應用中的圖片。要往App中添加一個靜態(tài)圖片,只需把圖片文件放在代碼文件夾中某處,然后像下面這樣去引用它:
<Image source={require('./my-icon.png')} />圖片文件的查找會和JS模塊的查找方式一樣。在上面的這個例子里,是哪個組件引用了這個圖片,Packager就會去這個組件所在的文件夾下查找my-icon.png。并且,如果你有my-icon.ios.png和my-icon.android.png,Packager就會根據平臺而選擇不同的文件。
你還可以使用@2x,@3x這樣的文件名后綴,來為不同的屏幕精度提供圖片。比如下面這樣的代碼結構:
.
├── button.js
└── img
├── check@2x.png
└── check@3x.png
并且button.js里有這樣的代碼:
<Image source={require('./img/check.png')} />Packager會打包所有的圖片并且依據屏幕精度提供對應的資源。譬如說,iPhone 5s會使用check@2x.png,而Nexus 5上則會使用check@3x.png。如果沒有圖片恰好滿足屏幕分辨率,則會自動選中最接近的一個圖片。
注意:如果你添加圖片的時候packager正在運行,可能需要重啟packager以便能正確引入新添加的圖片。
-
這樣會帶來如下的一些好處:
- iOS和Android一致的文件系統(tǒng)。
- 圖片和JS代碼處在相同的文件夾,這樣組件就可以包含自己所用的圖片而不用單獨去設置。
- 不需要全局命名。你不用再擔心圖片名字的沖突問題了。
- 只有實際被用到(即被require)的圖片才會被打包到你的app。
- 現在在開發(fā)期間,增加和修改圖片不需要重新編譯了,只要和修改js代碼一樣刷新你的模擬器就可以了。
- 與訪問網絡圖片相比,Packager可以得知圖片大小了,不需要在代碼里再聲明一遍尺寸。
- 現在通過npm來分發(fā)組件或庫可以包含圖片了。
注意:為了使新的圖片資源機制正常工作,require中的圖片名字必須是一個靜態(tài)字符串。
// 正確
<Image source={require('./my-icon.png')} />
// 錯誤
var icon = this.props.active ? 'my-icon-active' : 'my-icon-inactive';
<Image source={require('./' + icon + '.png')} />
// 正確
var icon = this.props.active ? require('./my-icon-active.png') : require('./my-icon-inactive.png');
<Image source={icon} />
- 本特性從0.14開始生效。請注意:新的資源系統(tǒng)依靠修改打包腳本來實現,react-native init創(chuàng)建的新工程已經包含了這些修改:Xcode和Gradle。如果你的工程是在0.13或者更早版本創(chuàng)建的,你可能需要自行添加對應的代碼來支持新的圖片資源系統(tǒng)。請參考文檔升級版本文檔中的升級操作說明。
使用混合App的圖片資源
- 如果你在編寫一個混合App(一部分UI使用React Native,而另一部分使用平臺原生代碼),也可以使用已經打包到App中的圖片資源(通過Xcode的asset類目或者Android的drawable文件夾打包):
<Image source={{uri: 'app_icon'}} style={{width: 40, height: 40}} />
- 注意:這一做法并沒有任何安全檢查。你需要自己確保圖片在應用中確實存在,而且還需要指定尺寸。
網絡圖片
- 很多要在App中顯示的圖片并不能在編譯的時候獲得,又或者有時候需要動態(tài)載入來減少打包后的二進制文件的大小。這些時候,與靜態(tài)資源不同的是,你需要手動指定圖片的尺寸。
// 正確
<Image source={{uri: 'https://facebook.github.io/react/img/logo_og.png'}}
style={{width: 400, height: 400}} />
// 錯誤
<Image source={{uri: 'https://facebook.github.io/react/img/logo_og.png'}} />
本地文件系統(tǒng)中的圖片
- 參考相冊(CameraRoll)這個例子來看如何使用在Images.xcassets以外的本地資源。
最合適的相冊圖片
- iOS會為同一張圖片在相冊中保存多個不同尺寸的副本。為了性能考慮,從這些副本中挑出最合適的尺寸顯得尤為重要。對于一處200x200大小的縮略圖,顯然不應該選擇最高質量的3264x2448大小的圖片。如果恰好有匹配的尺寸,那么React Native會自動為你選好。如果沒有,則會選擇最接近的尺寸進行縮放,但也至少縮放到比所需尺寸大出50%,以使圖片看起來仍然足夠清晰。這一切過程都是自動完成的,所以你不用操心自己去完成這些繁瑣且易錯的代碼。
為什么不在所有情況下都自動指定尺寸呢?
在瀏覽器中,如果你不給圖片指定尺寸,那么瀏覽器會首先渲染一個0x0大小的元素占位,然后下載圖片,在下載完成后再基于正確的尺寸來渲染圖片。這樣做的最大問題是UI會在圖片加載的過程中上下跳動,使得用戶體驗非常糟糕。
在React Native中我們有意避免了這一行為。如此一來開發(fā)者就需要做更多工作來提前知曉遠程圖片的尺寸(或寬高比),但我們相信這樣可以帶來更好的用戶體驗。然而,從已經打包好的應用資源文件中讀取圖片(使用require('image!x')語法)則無需指定尺寸,因為它們的尺寸在加載時就可以立刻知道。
比如這樣一個引用require('image!logo')的實際輸出結果可能是:
{"__packager_asset":true,"isStatic":true,"path":"/Users/react/HelloWorld/iOS/Images.xcassets/react.imageset/logo.png","uri":"logo","width":591,"height":573}
資源屬性是一個對象(object)
- 在React Native中,另一個值得一提的變動是我們把src屬性改為了source屬性,而且并不接受字符串,正確的值是一個帶有uri屬性的對象。
<Image source={{uri: 'something.jpg'}} />
通過嵌套來實現背景圖片
- 開發(fā)者們常面對的一種需求就是類似web中的背景圖(background-image)。要實現這一用例,只需簡單地創(chuàng)建一個<Image>組件,然后把需要背景圖的子組件嵌入其中即可。
return (
<Image source={...}>
<Text>Inside</Text>
</Image>
);
在主線程外解碼圖片
- 圖片解碼有可能會需要超過一幀的時間。在web上這是頁面掉幀的一大因素,因為解碼是在主線程中完成的。然而在React Native中,圖片解碼則是在另一線程中完成的。在實際開發(fā)中,一般對圖片還沒下載完成時的場景都做了處理(添加loading等),而圖片解碼時顯示的占位符只占用幾幀時間,并不需要你改動代碼去額外處理。