密度非依存ピクセル
Vega上のReact Native 0.83では、デフォルトのレンダリング単位が密度非依存ピクセル(dp)になります。このページでは、単位の変更と、アプリ内のレイアウト値、入力処理、カスタムネイティブインターフェイス、画像の更新方法について説明します。内容はコード移行の手順4.9を補足するものです。
RN 0.83では、レイアウト値、コンポーネントの寸法、変換、スクロールオフセット、ポインター座標がすべて論理dpで表現されます。Vegaは、レンダリング境界でこれらの論理値を物理ピクセルに一度だけ変換します。アプリがRN 0.72の物理出力に合わせて調整されている場合は、出荷前にすべての数値レイアウト値を確認してください。
密度非依存ピクセル(DIP)について
dpは論理的なUI単位です。Vegaはこれをディスプレイのスケール係数を使用して物理ピクセルにマッピングします。
物理ピクセル = dp × スケール係数
dp = 物理ピクセル ÷ スケール係数
React Native 0.83より前のバージョンでは、dpレンダリングが無効になっているアプリは、width: 100を100物理ピクセルとして描画していました。React Native 0.83以降では、同じ値が100dpを意味します。Vegaは、これをスケール係数2の場合は200物理ピクセル、スケール係数2.66の場合は266物理ピクセルとして描画します。これが評価すべき主なレイアウトへの影響です。
Vegaのキャンバスの基準サイズは960x540dpで、1080pディスプレイでのスケール係数は2になります。
単位変更の対象範囲
RN 0.83では、UIパス全体にdpマッピングが適用されます。
- Vegaは最終的な描画キャンバスとダメージ領域をスケーリングします。
- ウィンドウのサイズと位置はグラフィックス境界を越える際に物理ピクセルになりますが、アプリコード内ではdpのままです。
- ポインター、タッチ、リサイズ、ウィンドウ位置、オクルージョンの各イベントはdpとしてReact Nativeに返されます。
- 子ウィンドウ、ポップアップ、モーダル、テクスチャキャッシュされたレイヤー、仮想サーフェスは、同じスケールを使用します。
DimensionsとuseWindowDimensions()は論理寸法を返します。PixelRatio.get()は、物理ピクセルとdpの比率を返します。
単位変更の対象ではないもの
以下の2つの領域では、既存の動作が維持されます。
- ビットマップデータ。dpレンダリングはビットマップデータをスケーリングしたり、画像メタデータを変更したりしません。画像デコーダー、ビットマップ、ピクスマップ、テクスチャでは、引き続き物理ピクセル単位の寸法が使用されます。
- フォントのスケーリング。dpレンダリングは、アクセシビリティのフォントスケーリングに代わるものではありません。ユーザーが選択したテキストサイズについては、React NativeのテキストAPIと
fontScaleを引き続き使用してください。
PixelRatioとDeviceInfoターボモジュール
PixelRatioはReact Native JavaScriptユーティリティであり、スタンドアロンのターボモジュールではありません。PixelRatio.get()はDimensions.get('window').scaleを読み取ります。ネイティブのDeviceInfoターボモジュールは、width、height、scale、fontScaleをDimensionsに提供します。
RN 0.83では、DeviceInfoが論理ウィンドウ寸法(dp)と、現在の物理ピクセルからdpへのスケール値を報告します。また、didUpdateDimensionsを通じて、サーフェスごとの寸法の更新も公開します。
PixelRatio.get()は、コードでスケール係数を検査する必要がある場合にのみ使用してください。Vegaは既にそれらの値をスケーリングしているため、標準のReact Nativeレイアウト値には適用しないでください。Vegaで密度非依存ピクセルを使用する理由
AndroidとiOS上のReact Nativeは、デフォルトで論理単位を使用します。VegaはRN 0.83アプリに同じデフォルト座標モデルを採用しているため、ジオメトリは3つのターゲットすべてで同じように動作します。
標準のReact Nativeコンポーネント、カスタムネイティブコンポーネント、ターボモジュール、サードパーティライブラリ、ウィンドウAPI、レンダリング、入力イベントは、1つの単位契約でカバーされるようになりました。アプリはUIジオメトリを論理単位で記述し、Vegaはそのジオメトリをグラフィック境界で変換します。UIの比率は、キャンバス解像度の異なるデバイス間で一定に保たれます。Scalable UIでは、個別のピクセルレイアウトなしで高解像度のキャンバスを選択できます。
アプリでの変更
次の表は、一般的なRN 0.72のパターンとRN 0.83での動作の対応を示しています。
| アプリ内のパターン | RN 0.83での動作 | 対処方法 |
|---|---|---|
数値の長さスタイルとYogaの定数(width: 100など)、マージン、パディング、ボーダー、オフセット |
値が100の場合、100 × scaleFactorの物理ピクセルとしてレンダリングされます。 |
ピクセル調整値をlogicalValue = legacyPixelValue ÷ baselineScaleFactorで変換します。 |
| Flexboxとパーセンテージによるサイズ指定 | 値は論理ビューポートに対して相対的なままです。 | 単位変換なし。結果のレイアウトを検証します。 |
ハードコーディングされた1920 × 1080の画面ジオメトリ |
レイアウトが現在の論理ビューポートと一致しなくなっています。 | useWindowDimensions()、Flexbox、パーセンテージを使用します。 |
ポインター/スクロール座標をPixelRatio.get()で除算した値 |
イベントは既にdp単位で渡されています。 | 手動での除算を削除します。 |
| Vega UI APIを呼び出すカスタムネイティブコンポーネント | Vega UI APIはジオメトリをdpとして解釈します。 | React Nativeの値を変換せずに渡します。 |
| 密度ごとに用意された個別のラスターアセット | コンポジターが不十分な解像度のソースをアップスケールします。 | 密度ごとのバリアントを追加するか、より大きなリモート画像をリクエストします。 |
ピクセル調整値の変換
RN 0.83では、数値の長さ指定はdpになります。移行前の基準となるスケール係数を使用して、物理ピクセルとして調整していた値を変換します。
論理値 = 従来の物理ピクセル値 ÷ 基準のスケール係数
以前にスケール係数2で調整されていたアプリの場合:
// ❌ 更新前(RN 0.72)- 物理的な出力に合わせて調整された値
const legacyStyles = StyleSheet.create({
card: {
width: 320,
height: 180,
borderRadius: 12,
},
});
//✅ 更新後(RN 0.83)- 物理サイズは同じで、dpで表されます
const styles = StyleSheet.create({
card: {
width: 160,
height: 90,
borderRadius: 6,
},
});
物理ピクセルとして調整していたマージン、パディング、ボーダー、変換、シャドウ、アニメーション距離、SVGの寸法、カスタムキャンバス座標にも同じ変換を適用します。密度非依存のUX仕様から既に値を取得している場合は、値を変更しないでください。
固定画面寸法の置き換え
ハードコーディングされた画面定数は、論理ビューポートを記述しません。代わりに実行時に寸法を読み取ってください。
// ❌ 更新前(RN 0.72)
const screenWidth = 1920;
const panelWidth = screenWidth / 3;
// ✅ 更新後(RN 0.83)
function Panel() {
const {width} = useWindowDimensions();
return <View style={{width: width / 3, height: '100%'}} />;
}
useWindowDimensions()は論理寸法を返します。React Nativeスタイルを割り当てる前に、それらを物理ピクセルに変換しないでください。
論理入力座標の使用
RN 0.83は、ポインター座標とタッチ座標をdp単位で返します。
const {pageX: x, pageY: y} = event.nativeEvent;
これらの値は、レイアウト、ジェスチャー、フォーカス、ヒットテスト、スクロール、アニメーションのコードへそのまま渡します。既にdp単位で渡されている座標をアプリ側で変換している場合は、その変換を削除します。そうしないと値が二重にスケーリングされます。
dp単位でのカスタムネイティブインターフェイスの保持
カスタムコンポーネントやターボモジュールのジオメトリは、React Nativeの境界でdpとして定義します。
NativeCardModule.setBounds({x, y, width, height}); // すべての値はdpです。
ネイティブ実装がVegaのウィンドウ、ビュー、レイヤー、キャンバスAPIを呼び出す場合、これらの値を変更せずにそのまま渡してください。物理ピクセルで定義されているAPI(ビットマップデコーダーや、より低レベルのグラフィックスAPIなど)を呼び出す場合にのみ、アクティブなスケール係数で変換します。両方の単位を1つのモジュールで使用する場合は、widthDpやtargetWidthPxのように、単位を名前に含めてください。
画像の処理
画像レイアウトと画像データは、異なる単位を使用します。
<Image style=>ではdpが使用されます。- ソースビットマップの寸法、デコード後の画像寸法、行のバイト数、テクスチャの寸法には、物理ピクセルが使用されます。
- React Nativeが論理的なデコードサイズを指定した場合、Vegaの画像パイプラインはデコード前にその値にアクティブなスケール係数を乗算します。独自のコードでは、
<Image>スタイルや目的のレイアウトサイズに対して乗算処理を行わないでください。 - レンダリングされるdpサイズに対して、ソース画像には十分な物理ピクセルが必要になります。たとえば、320×180dpで描画され、スケール係数が2の場合、アップスケーリングを避けるには少なくとも640×360のソースピクセルが必要になります。
ローカルアセット
同じディレクトリ内に密度別のバリアントを配置してください。MetroとReact Nativeは、アクティブな密度に一致するアセットを選択します。
assets/
icon.png
icon@2x.png
icon@3x.png
<Image source={require('./assets/icon.png')} style={{width: 48, height: 48}} />
2.66のような端数の密度の場合は、@3xのデータを用意してください。React Nativeは、低解像度のソースをアップスケーリングする代わりに、より高解像度のアセットを選択します。アイコンやその他の写真以外のアートワークには、SVGを使用することをお勧めします。
移行チェックリスト
dpの移行を完了するには、次の手順を実行してください。
- アプリをRN 0.83にアップグレードし、新しいデフォルト動作と重複するRN 0.72のdp実験用フラグをすべて削除します。
- アプリ内の数値による長さ指定、
1920や1080といった固定キャンバス定数、座標変換用のヘルパーをすべて確認します。 - 物理ピクセルとして調整されていた値は、
logicalValue = legacyPixelValue ÷ baselineScaleFactorの式で論理値に変換します。密度非依存のUX仕様に由来する値は、変更せずにそのまま残してください。 - RN 0.83によって報告されるポインター、ジェスチャー、スクロール、リサイズ、ウィンドウの座標は、dpとして扱います。
- React-Nativeからネイティブへのカスタムジオメトリコントラクトをdpに変更し、ドキュメント化されたピクセルAPIでのみピクセル変換を維持します。
- 固定画面寸法をFlexbox、パーセンテージ、
Dimensions、useWindowDimensions()を使用して置き換えます。 - ローカルのラスター密度バリアントを追加し、各画像が論理サイズで描画される際に十分な物理ピクセルを持っていることを確認します。
- メインウィンドウ、モーダル、ポップアップ、アラート、子ウィンドウ、スクロール、ジェスチャー、フォーカス、アクセシビリティ、ローカリゼーション、右から左へのレイアウトを、サポートされている各密度でテストします。
関連トピック
- 手順4: コードを移行する
- React Native 0.83へのアプリの移行
- PixelRatio
- useWindowDimensions
- レイアウトの測定(英語のみ)
- React Native 0.83への移行に関する問題のトラブルシューティング
外部リソース
- React Native PixelRatio(英語のみ)
- React Native Images(英語のみ)
Last updated: 2026年8月19日

