数日前、iPhone 向けに Rork で組んだ小さなツールアプリを、たまたま手元の iPad Air で開いてみたところ、思っていた以上に絵が崩れていました。生成された UI はきれいに動くのですが、片手で握って使う iPhone と、両手で抱えて使う iPad では、ボタン位置や余白の感覚がまるで違います。「動く」と「使える」のあいだに、こんなに距離があるのかと改めて感じた瞬間でした。
私自身、2014年から個人で iOS アプリを作り続けていて、累計5,000万DLほどになる壁紙アプリも iPad 対応をあとから入れたクチです。今回 Rork の生成物に対して3週間かけて手を入れる中で、いくつか共通する勘どころが見えてきました。本記事はその記録です。
iPad で開いた瞬間に見えた、3つの違和感
最初に iPad シミュレータで開いたとき、頭で考える前に「これは無理だ」と直感的に分かったポイントが3つありました。
ひとつ目は、コンテンツ全体が画面いっぱいに引き伸ばされてしまうことです。iPhone のときは収まりがよかったカードコンポーネントが、iPad では横長に潰れて、写真のトリミングが不自然に見えます。とくに壁紙の縦長サムネイルは、横幅をめいっぱい使うと「もうこれは別のアプリだ」と感じるほど印象が変わりました。
ふたつ目は、タップターゲットの密度です。iPhone では親指で押す前提で 56pt 程度の余白を取っていたボタンが、iPad では手のひらと指の関係が変わるため、隣のボタンと干渉しやすくなりました。実際、自分で誤タップを起こしました。
みっつ目は、SafeArea の前提が崩れることです。Rork が生成したレイアウトは iPhone のノッチや Home Indicator を意識した余白配置になっており、iPad では上下のセーフエリアが思いのほか細く、結果として画面の上下に違和感のある空白が残りました。
3週間の作業は、おおむねこの3つの違和感を、ひとつずつ自分の目で確かめながらほどいていく作業でした。順番としては、まず画面の骨格である「最大幅とコンテナ」、次に「ボタンと余白の感覚」、最後に「画像とキーボード周辺」という流れで手を入れていきました。
最大幅とコンテナをやり直した話
最初に手を入れたのは、ルートレイアウトの「最大幅」と「中央寄せ」です。
iPhone を前提に組まれた Rork の生成物は、flex: 1 で画面いっぱいに広がる構造が多く、iPad ではそのまま使うと情報の密度が下がりすぎます。私は壁紙アプリで以前学んだ通り、コンテンツ側に最大幅を持たせて、両端に余白を残す方針に切り替えました。
import { View, useWindowDimensions } from 'react-native';
function ContentContainer({ children }: { children: React.ReactNode }) {
const { width } = useWindowDimensions();
// iPad 縦持ち相当(768pt 以上)で読み物の上限幅を抑える
const maxWidth = width >= 768 ? 720 : width;
return (
<View style={{ width: '100%', alignItems: 'center' }}>
<View style={{ width: '100%', maxWidth, paddingHorizontal: 20 }}>
{children}
</View>
</View>
);
}この ContentContainer を画面のルートに差し込むだけで、iPad では画面中央に 720pt 幅で収まり、両脇に余白が生まれます。読み物としての落ち着きが戻り、横長のカードが不自然に潰れる問題も大半が消えました。
ポイントは、maxWidth を機種ではなく width から判定していることです。Split View や Slide Over の幅変化にも自然に追従しますし、将来 Stage Manager のような可変ウィンドウが当たり前になっても壊れにくくなります。私は iPad の Split View で半分ずつアプリを並べて使う癖があるので、ここで機種判定に頼ってしまうと、Split View のときだけ妙にスカスカな画面になってしまうのです。
タッチターゲットと余白の感覚を作り直した話
次に手を入れたのは、ボタンと余白の感覚です。
iPhone では 44〜56pt のタップ高で十分でしたが、iPad で両手持ちのまま親指を立てて使うシチュエーションでは、その高さだとボタンの境界が見えづらく、何度か誤タップを起こしました。私は次の方針で揃え直しました。
- 主要なボタンの最小高さは 52pt(iPhone)/60pt(iPad)
- ボタン間の最小ギャップは 12pt(iPhone)/20pt(iPad)
- カード同士の縦余白は 16pt(iPhone)/24pt(iPad)
これは個人の手の大きさにも依存するので、決定打というよりは「私の手と私のテスト機材ではここが最も誤タップが減った」という所感です。実際、家族の誰かに渡して触ってもらうと、また少し違う数値が出てくるかもしれません。
実装は、Rork の生成物が StyleSheet.create をそのまま使っているので、デザイントークン的な定数を一段挟む方針にしました。
// theme/spacing.ts
import { useWindowDimensions } from 'react-native';
export function useSpacing() {
const { width } = useWindowDimensions();
const isTablet = width >= 768;
return {
tapMin: isTablet ? 60 : 52,
gap: isTablet ? 20 : 12,
cardGap: isTablet ? 24 : 16,
};
}ここまでくると、iPad で押し間違える回数が体感で半分以下になりました。Rork が生成した個別のコンポーネントは触らず、トークンだけ差し替える形に寄せたので、後で生成物を差し替えてもこの調整は残ります。
12年の壁紙アプリ運用で培った「壊れにくい」設計の癖
ここで少し、個人開発12年で身に染みた癖の話をさせてください。
私の両家の祖父はそれぞれ宮大工をしていました。子どもの頃に祖父の手元を眺めていると、釘を打つ前に必ず木の癖を確かめてから、力を入れる場所を決めていました。「素材の癖に逆らわず、長く持つように組む」というあの感覚は、いまでもアプリの設計の中に残っています。
レスポンシブ対応も同じで、機種ごとの分岐を増やすほどコードはもろくなります。Platform.isPad のような「機種そのもの」で分岐するのではなく、width や aspectRatio のような「いまの形」で分岐するほうが、Foldable や折りたたみ iPhone のような将来の形にも素直に耐えます。
たとえばカードのカラム数を切り替えたいときに、私はいつも次のような書き方を選びます。
function useColumnCount() {
const { width } = useWindowDimensions();
if (width >= 1024) return 4; // iPad 横持ち相当
if (width >= 768) return 3; // iPad 縦持ち相当
if (width >= 480) return 2; // 大きめの iPhone 横向き
return 1;
}5,000万DL を超える壁紙アプリの運用では、機種別 if 文がどんどん増えて保守を難しくする失敗を、自分の手で何度かやってきました。あの頃の自分に、いまの私が伝えたいことを、コードのほうに残しておきたいと思っています。
もうひとつ、宮大工の祖父から借りている考え方があります。それは「直したあとに、直す前より素直になっているか」を毎回確かめることです。コードでも同じで、対応を入れたあとに条件分岐が増え、人間が読むときの段差が増えているなら、それは木目に逆らった釘打ちと同じだと、自分に言い聞かせています。
いま続けている3週間目以降の調整
3週間で全部が終わったわけではなく、いまも続いている調整がいくつかあります。
ひとつは、画像読み込みの最適化です。iPhone のときは標準解像度で十分だった壁紙サムネイルが、iPad の Retina ディスプレイでは荒く見えるケースがあり、expo-image の transition と placeholder を組み合わせて、ストレスのない切り替わりを作り直しています。配信側でも 1x/2x/3x の三段階のアセットを返すように直しました。
もうひとつは、キーボード周りです。iPad ではソフトウェアキーボードが半透明で出現し、外付けキーボード接続時はキーボード自体が出ないため、KeyboardAvoidingView の挙動を見直す必要がありました。これは Rork の生成テンプレートに任せきりにすると、iPad では入力欄が隠れたまま戻らない事故を起こします。私の壁紙アプリでは検索欄が唯一のキーボード入力なので、対策をその1か所だけに絞り込めましたが、フォームの多いアプリではもう少し体系的な見直しが要りそうです。
最後に、テストの仕方です。iPad シミュレータでの目視確認はもちろんですが、自宅の iPad Air、家族の使っている iPad mini、そして週末に立ち寄った Apple Store の iPad Pro でも触らせてもらい、「自分の手とは違う手で押せるか」を確かめています。個人開発の弱点は手の感覚が固定化してしまうことなので、ここだけは時間を作って外に出るようにしています。
3週間ぶんの作業をひとことでまとめるなら、「Rork の生成物はよくできているけれど、iPad で『使える』状態に持っていくには、人間の手の感覚を一度通す必要がある」というのが正直な所感です。次は同じアプリを Vision Pro のシミュレータでも開いてみる予定で、その記録もどこかで残せたらと思っています。
お読みいただきありがとうございました。同じように iPad 対応を後追いで進めている方の、ささやかな参考になれば幸いです。