スタックナビゲーション
モバイルアプリで最も一般的なナビゲーションパターンのひとつが「スタックナビゲーション」です。これは、新しい画面が前の画面の上に積み重なるように表示され、ユーザーは「戻る」操作で前の画面に戻ることができる、というものです。
例えば、商品一覧画面から商品詳細画面へ遷移し、さらにレビュー投稿画面へ進む、といった一連の流れを想像すると分かりやすいでしょう。多くのOSで標準的な「戻る」ボタン(ヘッダーの左矢印や、Androidの物理/ジェスチャーバックボタン)がこのスタックの操作と連動します(図4)。
Expo Routerでは、このスタックナビゲーションを簡単に実装するための仕組みが提供されています。expo-routerパッケージに含まれるStackコンポーネントをレイアウトルート (_layout.js) で使用します。
基本的なスタックナビゲーションの設定
特定の画面群(例えば設定関連の画面すべて)にスタックナビゲーションを適用したい場合、それらの画面ファイルを一つのディレクトリにまとめ、そのディレクトリ直下にレイアウトルートファイル (_layout.js) を作成します。そして、この_layout.jsからStackコンポーネントをエクスポートします。
例として、app/settings/ディレクトリ内に設定関連の画面 (index.js, profile.js, notifications.js) を配置し、これらをスタックナビゲーションで管理するケースを考えます。ファイル構成はリスト3のようになります。
app/ ├── settings/ │ ├── _layout.js // settingsディレクトリ用スタックナビゲーションのレイアウト │ ├── index.js // /settings (設定トップ画面) │ ├── profile.js // /settings/profile (プロフィール編集画面) │ └── notifications.js // /settings/notifications (通知設定画面) └── _layout.js // アプリ全体のルートレイアウト
図4のようなイメージの画面遷移ができるとよいですね。
これを実現するには、app/settings/_layout.jsの内容はリスト4のようになります。
// app/settings/_layout.js
import { Stack } from 'expo-router';
export default function SettingsStackLayout() {
return (
<Stack>
{/* (1) 各画面のヘッダー設定などをここで行う */}
<Stack.Screen name="index" options={{ title: '設定' }} />
<Stack.Screen name="profile" options={{ title: 'プロフィール編集' }} />
<Stack.Screen name="notifications" options={{ title: '通知設定' }} />
</Stack>
);
}
このapp/settings/_layout.jsが、settingsディレクトリ内のすべての画面ファイル (index.js, profile.js, notifications.js) に対する共通レイアウトとして機能します。Stackコンポーネントを返すことで、これらの画面がスタックとして管理されるようになります。
(1)のようにStackコンポーネントの子要素として<Stack.Screen name="ファイル名" options={{...}} />を記述することで、各画面がスタックに登録され、ヘッダーのタイトル ( options={{ title: '...' }}) などのナビゲーションオプションを指定できます。
name属性には、settingsディレクトリ内のファイル名(拡張子なし)を指定します。例えばindex.jsならindex、profile.jsならprofileです。
これにより、/settings(settings/index.js) から/settings/profile (settings/profile.js) へLinkコンポーネントで遷移すると、profile.jsの画面がindex.jsの画面の上に重なって表示され、ヘッダーには自動的に「戻る」ボタンと「プロフィール編集」というタイトルが表示されます(図6)。
スタックナビゲーションを利用することで、進んだり戻ったりする基本的な画面遷移を簡便に実装できますね。
タブナビゲーション
スタックナビゲーションと並んで、モバイルアプリで頻繁に用いられるのが「タブナビゲーション」です。
これは通常、画面の下部(時には上部)に複数のタブが配置され、各タブをタップすることで対応する画面に切り替わるというインターフェースです。アプリの主要な機能セクションへのショートカットとして機能し、ユーザーは少ない操作で目的の画面に素早くアクセスできます(図7)。
Expo Routerでは、このタブナビゲーションもexpo-routerパッケージに含まれるTabsコンポーネントをレイアウトルート (_layout.js) で使用することで簡単に実装できます。
基本的なタブナビゲーションの設定
タブナビゲーションをアプリの主要な画面群(例:ホーム、検索、マイページなど)に適用するには、これらの画面をグループルートでまとめ、そのグループのレイアウトルート (app/(tabs)/_layout.jsなど) で Tabsコンポーネントをデフォルトエクスポートします。
例えば、ホーム画面 (home.js)、検索画面 (search.js)、マイページ画面 (mypage.js) をタブで切り替えられるようにしたい場合、リスト5のようなファイル構成になります。
app/ ├── (tabs)/ │ ├── _layout.js // タブナビゲーションのレイアウト定義 │ ├── home.js // /home (ホーム画面) │ ├── search.js // /search (検索画面) │ └── mypage.js // /mypage (マイページ画面) └── _layout.js // アプリ全体のルートレイアウト
これらのファイルをタブナビゲーションで扱うには、リスト6のように登録します。
// app/(tabs)/_layout.js
import { Tabs } from 'expo-router';
import { FontAwesome } from '@expo/vector-icons'; // アイコン表示のため
export default function TabLayout() {
return (
<Tabs
screenOptions={{ // (6)
// tabBarActiveTintColor: 'blue', // アクティブなタブの色などを指定できる
}}
>
<Tabs.Screen
name="home" // (1)
options={{ // (2)
title: 'ホーム', // (3)
tabBarIcon: ({ color, size }) => ( // (4)
<FontAwesome name="home" size={size} color={color} />
),
}}
/>
<Tabs.Screen
name="search"
options={{
title: '検索',
tabBarIcon: ({ color, size }) => (
<FontAwesome name="search" size={size} color={color} />
),
}}
/>
<Tabs.Screen
name="mypage"
options={{
title: 'マイページ',
tabBarIcon: ({ color, size }) => (
<FontAwesome name="user" size={size} color={color} />
),
// (5)
headerShown: false, // ヘッダーを非表示にする場合
}}
/>
</Tabs>
);
}
この(tabs)/_layout.jsが、(tabs)ディレクトリ内のすべての画面 (home.js, search.js, mypage.js) に対するレイアウトとして機能し、Tabsコンポーネントを返すことで、これらの画面がタブインターフェースで管理されるようになります。Tabsコンポーネントの直下には<Tabs.Screen ... />を配置し、各タブに対応する画面を指定します。
(1)のname属性には、グループルート内のファイル名(拡張子なし)を指定します。(2)の options属性では、各タブの見た目や挙動をカスタマイズします。(3)のtitleプロパティはタブのラベルや、そのタブが選択されている時のヘッダータイトルとして使用されます。(4)のtabBarIconは、タブに表示されるアイコンを指定する関数です。引数としてcolorと sizeを受け取り、アイコンコンポーネントを返します。上記の例では@expo/vector-iconsのFontAwesomeを使用しています。(5)のheaderShown: falseを指定すると、そのタブがアクティブな時にデフォルトで表示されるヘッダーを非表示にできます(図8)。
Tabsコンポーネント自体の設定である(6)のscreenOptionsプロパティでは、すべてのタブに共通のオプション(例:アクティブなタブのアイコンやラベルの色tabBarActiveTintColor)を指定することも可能です。
