画像
静的画像リソース
React Nativeは、AndroidおよびiOSアプリで画像やその他のメディアアセットを管理するための統一された方法を提供します。アプリに静的画像を追加するには、ソースコードツリー内のどこかに配置し、次のように参照します。
<Image source={require('./my-icon.png')} />
イメージ名は、JSモジュールが解決されるのと同じ方法で解決されます。上記の例では、バンドラは、それを必要とするコンポーネントと同じフォルダにある`my-icon.png`を探します。
異なる画面密度に合わせて画像を提供するために、`@2x`および`@3x`サフィックスを使用できます。次のファイル構造がある場合
.
├── button.js
└── img
├── check.png
├── check@2x.png
└── check@3x.png
…そして`button.js`コードには
<Image source={require('./img/check.png')} />
…が含まれている場合、バンドラはデバイスの画面密度に対応する画像をバンドルして提供します。たとえば、`check@2x.png`はiPhone 7で使用され、`check@3x.png`はiPhone 7 PlusまたはNexus 5で使用されます。画面密度に一致する画像がない場合は、最も近い最適なオプションが選択されます。
Windowsでは、プロジェクトに新しい画像を追加した場合、バンドラを再起動する必要がある場合があります。
得られる利点は次のとおりです。
- AndroidとiOSで同じシステム。
- 画像はJavaScriptコードと同じフォルダにあります。コンポーネントは自己完結型です。
- グローバル名前空間はありません。つまり、名前の衝突を心配する必要はありません。
- 実際に使用される画像のみがアプリにパッケージ化されます。
- 画像の追加と変更にはアプリの再コンパイルは必要ありません。通常どおりシミュレータを更新できます。
- バンドラは画像の寸法を知っているため、コードに複製する必要はありません。
- 画像はnpmパッケージを介して配布できます。
これが機能するには、`require`内のイメージ名が静的に認識されている必要があります。
// GOOD
<Image source={require('./my-icon.png')} />;
// BAD
const icon = this.props.active
? 'my-icon-active'
: 'my-icon-inactive';
<Image source={require('./' + icon + '.png')} />;
// GOOD
const icon = this.props.active
? require('./my-icon-active.png')
: require('./my-icon-inactive.png');
<Image source={icon} />;
このようにして必要とされる画像ソースには、Imageのサイズ(幅、高さ)情報が含まれています。画像を動的にスケーリングする必要がある場合(例:flexを使用)、スタイル属性で`{width: undefined, height: undefined}`を手動で設定する必要がある場合があります。
静的非画像リソース
上記で説明した`require`構文を使用して、オーディオ、ビデオ、またはドキュメントファイルをプロジェクトに静的に含めることもできます。` .mp3`、` .wav`、` .mp4`、` .mov`、` .html`、` .pdf`など、最も一般的なファイルタイプがサポートされています。バンドラのデフォルトで完全なリストを参照してください。
Metro設定ファイルに`assetExts`レゾルバーオプションを追加することで、他のタイプをサポートできます。Metro設定を参照してください。
注意点として、ビデオはサイズ情報が現在非画像アセットに対して渡されていないため、`flexGrow`ではなく絶対位置付けを使用する必要があります。この制限は、XcodeまたはAndroidのアセットフォルダに直接リンクされているビデオには発生しません。
ハイブリッドアプリのリソースからの画像
ハイブリッドアプリ(React Nativeの一部UI、プラットフォームコードの一部UI)を構築している場合でも、アプリに既にバンドルされている画像を使用できます。
XcodeアセットカタログまたはAndroidのdrawableフォルダを介して含まれる画像には、拡張子なしで画像名を使用します。
<Image
source={{uri: 'app_icon'}}
style={{width: 40, height: 40}}
/>
Androidのアセットフォルダにある画像には、`asset:/`スキームを使用します。
<Image
source={{uri: 'asset:/app_icon.png'}}
style={{width: 40, height: 40}}
/>
これらのアプローチは、安全チェックを提供しません。これらの画像がアプリケーションで使用可能であることを保証するのはあなたの責任です。また、画像の寸法を手動で指定する必要があります。
ネットワーク画像
アプリに表示する画像の多くは、コンパイル時に使用できないか、バイナリサイズを小さくするために動的に読み込む必要があります。静的リソースとは異なり、*画像の寸法を手動で指定する必要があります*。iOSのアプリトランスポートセキュリティ要件を満たすためにも、httpsを使用することを強くお勧めします。
// GOOD
<Image source={{uri: 'https://react.dokyumento.jp/logo-og.png'}}
style={{width: 400, height: 400}} />
// BAD
<Image source={{uri: 'https://react.dokyumento.jp/logo-og.png'}} />
画像のネットワークリクエスト
HTTP動詞、ヘッダー、または本文などの画像リクエストとともに設定したい場合は、ソースオブジェクトにこれらのプロパティを定義することで実行できます。
<Image
source={{
uri: 'https://react.dokyumento.jp/logo-og.png',
method: 'POST',
headers: {
Pragma: 'no-cache',
},
body: 'Your Body goes here',
}}
style={{width: 400, height: 400}}
/>
URIデータ画像
REST API呼び出しからエンコードされた画像データを取得する場合があります。これらの画像を使用するには、`'data:'` URIスキームを使用できます。ネットワークリソースと同様に、*画像の寸法を手動で指定する必要があります*。
これは、DBからのリスト内のアイコンなど、非常に小さく動的な画像にのみ推奨されます。
// include at least width and height!
<Image
style={{
width: 51,
height: 51,
resizeMode: 'contain',
}}
source={{
uri: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADMAAAAzCAYAAAA6oTAqAAAAEXRFWHRTb2Z0d2FyZQBwbmdjcnVzaEB1SfMAAABQSURBVGje7dSxCQBACARB+2/ab8BEeQNhFi6WSYzYLYudDQYGBgYGBgYGBgYGBgYGBgZmcvDqYGBgmhivGQYGBgYGBgYGBgYGBgYGBgbmQw+P/eMrC5UTVAAAAABJRU5ErkJggg==',
}}
/>
キャッシュコントロール(iOSのみ)
場合によっては、ローカルキャッシュに既に存在する場合にのみ画像を表示する場合があります(高解像度が使用可能になるまでの低解像度のプレースホルダーなど)。他のケースでは、画像が古くなっているかどうかは気にせず、帯域幅を節約するために古い画像を表示しても構いません。`cache`ソースプロパティを使用すると、ネットワークレイヤーがキャッシュとどのように対話するかを制御できます。
default
:ネイティブプラットフォームのデフォルトの戦略を使用します。reload
:URLのデータは元のソースからロードされます。既存のキャッシュデータを使用してURLロードリクエストを満たすことはありません。force-cache
:既存のキャッシュデータは、その年齢または有効期限に関係なく、リクエストを満たすために使用されます。リクエストに対応するキャッシュに既存のデータがない場合は、データが元のソースからロードされます。only-if-cached
:既存のキャッシュデータは、その年齢または有効期限に関係なく、リクエストを満たすために使用されます。URLロードリクエストに対応するキャッシュに既存のデータがない場合、元のソースからデータを読み込む試みは行われず、ロードは失敗したと見なされます。
<Image
source={{
uri: 'https://react.dokyumento.jp/logo-og.png',
cache: 'only-if-cached',
}}
style={{width: 400, height: 400}}
/>
ローカルファイルシステム画像
Images.xcassets
の外にあるローカルリソースの使用例については、CameraRollを参照してください。
最適なカメラロール画像
iOSはカメラロール内の同じ画像に対して複数のサイズを保存します。パフォーマンス上の理由から、可能な限り近いサイズを選択することが非常に重要です。200x200のサムネイルを表示するときに、3264x2448の高画質画像をソースとして使用したくありません。正確な一致がある場合、React Nativeはそれを選択します。そうでない場合は、サイズ変更時のぼやけを避けるために、少なくとも50%大きい最初のものを選択します。これらはすべてデフォルトで実行されるため、面倒でエラーが発生しやすいコードを自分で記述する必要はありません。
すべてを自動的にサイズ変更しないのはなぜですか?
ブラウザで画像のサイズを指定しない場合、ブラウザは0x0の要素をレンダリングし、画像をダウンロードしてから、正しいサイズで画像をレンダリングします。この動作における大きな問題は、画像の読み込み時にUIが周囲を飛び回ることで、非常に悪いユーザーエクスペリエンスになります。これは累積レイアウトシフトと呼ばれています。
React Nativeでは、この動作は意図的に実装されていません。開発者が事前にリモート画像の寸法(またはアスペクト比)を知るための作業が増えますが、より良いユーザーエクスペリエンスにつながると考えています。require('./my-icon.png')
構文を使用してアプリバンドルからロードされた静的画像は、マウント時にその寸法がすぐに利用できるため、自動的にサイズ調整できます。
例えば、require('./my-icon.png')
の結果は次のようになります。
{"__packager_asset":true,"uri":"my-icon.png","width":591,"height":573}
オブジェクトとしてのソース
React Nativeでは、興味深い決定の1つとして、src
属性がsource
という名前で、文字列ではなくuri
属性を持つオブジェクトを受け取ることが挙げられます。
<Image source={{uri: 'something.jpg'}} />
インフラストラクチャ側の理由としては、これによりメタデータオブジェクトに添付できるためです。例えば、require('./my-icon.png')
を使用している場合、実際の場所とサイズに関する情報が追加されます(この事実に依存しないでください。将来変更される可能性があります!)。これは将来性も考慮した設計であり、例えば、将来的にスプライトをサポートしたい場合、{uri: ...}
を出力する代わりに、{uri: ..., crop: {left: 10, top: 50, width: 20, height: 40}}
を出力し、既存のすべての呼び出し箇所でスプライトを透過的にサポートできます。
ユーザー側では、これにより、表示されるサイズを計算するために、画像の寸法などの有用な属性でオブジェクトに注釈を付けることができます。画像に関するより多くの情報を格納するためのデータ構造として自由に使用してください。
ネストによる背景画像
Webに精通している開発者からの一般的な機能要求として、background-image
があります。このユースケースを処理するために、<Image>
と同じpropsを持ち、上に重ねたい子コンポーネントを追加できる<ImageBackground>
コンポーネントを使用できます。
実装が基本的なため、場合によっては<ImageBackground>
を使用しない方が良い場合があります。より詳しい情報については、<ImageBackground>
のドキュメントを参照し、必要に応じて独自のカスタムコンポーネントを作成してください。
return (
<ImageBackground source={...} style={{width: '100%', height: '100%'}}>
<Text>Inside</Text>
</ImageBackground>
);
幅と高さのスタイル属性を指定する必要があることに注意してください。
iOSの角丸スタイル
次の角に固有の角丸スタイルのプロパティは、iOSの画像コンポーネントによって無視される可能性があることに注意してください。
borderTopLeftRadius
borderTopRightRadius
borderBottomLeftRadius
borderBottomRightRadius
オフスレッドデコード
画像のデコードには、1フレーム分の時間以上かかる場合があります。デコードがメインスレッドで行われるため、これはWebでのフレームドロップの主な原因の1つです。React Nativeでは、画像のデコードは別のスレッドで行われます。実際には、画像がまだダウンロードされていない場合を既に処理する必要があるため、デコード中にプレースホルダーをさらに数フレーム表示しても、コードの変更は必要ありません。
iOSの画像キャッシュ制限の構成
iOSでは、React Nativeのデフォルトの画像キャッシュ制限をオーバーライドするためのAPIを提供しています。これは、ネイティブのAppDelegateコード内(例:didFinishLaunchingWithOptions
内)から呼び出す必要があります。
RCTSetImageCacheLimits(4*1024*1024, 200*1024*1024);
パラメータ
名前 | 型 | 必須 | 説明 |
---|---|---|---|
imageSizeLimit | 数値 | はい | 画像キャッシュのサイズ制限。 |
totalCostLimit | 数値 | はい | 総キャッシュコスト制限。 |
上記のコード例では、画像サイズ制限は4MB、総コスト制限は200MBに設定されています。