Ionic Frameworkを使ってモバイル画面の限られたスペースで複数のコンテンツを表示する4個の方法

この記事は、 [Ionic Framework / Capacitor / Stencil Advent Calendar 2022](https://qiita.com/advent-calendar/2022/ionic_jp) の1日目の記事です。

さて、モバイル画面を設計していると、モバイル画面の限られたスペースに複数のコンテンツパターンを詰め込むことに悩むことも少なくないと思います。ハンバーガーメニューを用意して、縦にずらっとメニューを並べるようなことをすればその悩みからは開放されますが、逆にユーザからするとメニューが多すぎて何をどう使えばいいかわからないUIになります。そこで、タブをベースにしたメニューの考え方についてまとめようと思います。

# 整理のステップ
## 1. コンテンツを最大5つに絞り込む

> Use the minimum number of tabs required to help people navigate your app. Each additional tab increases the complexity of your app, making it harder for people to locate information. Aim for a few tabs with short titles or icons to avoid crowding and causing tabs to truncate. In general, use three to five tabs in iOS; use a few more in iPadOS and tvOS if necessary.

HIGで紹介されているように、タブ数は絞り込まれるべきで、3-5つにすることが推奨されています。

https://developer.apple.com/design/human-interface-guidelines/components/navigation-and-search/tab-bars/

タブが横にスライドできるのは論外としても、6つ7つタブを用意しないといけないのはコンテンツ設計を失敗してるといえるでしょう。

例えばFacebookだと、以下のようになります。

- ニュースフィード
- 友達を検索
- Facebook Watch
- お知らせ
- その他

Twitterだと以下の通りです。

- ホーム
- 検索
- コミュニティ
- 通知
- DM

Twitterの秀逸なところとして、一般的にその他に分類されるアカウント制御などは左上の自分のユーザアイコンをタップすると横からメニューがでてきて設定できるようになるようしてることが挙げられます。ここらはTwitter利用の文脈だとユーザが利用する回数は少ないので、常時目にするタブではなく、「どのアカウントでログインしているか」を判断できるユーザアイコンをボタンとしてメニュー出すのはよく考えられてるなと思います。

ということで、まずモバイル画面の限られたスペースでコンテンツ表示をするためには、アプリの機能を最大5つ（Twitterのような方法を採用するなら、その他を別に移動する前提で6つ）に絞り込んでタブに振り分ける必要があります。

## 2. タブの従属を整理する

例えば、Twitterの「検索」には、その下位コンテンツに「初期表示するおすすめトピック」があります。

![スクリーンショット 2022-11-28 午後5.37.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100460/bd2b44fc-b22b-9cbf-233a-3618509c2d2d.png)

あと、キーワード検索をタップすると表示される検索履歴。

![スクリーンショット 2022-11-28 午後5.38.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100460/b8ff34b0-a923-6b6c-1e05-6f5ed6c1c682.png)

そして、検索すると、検索ワードに紐ついて表示されるコンテンツです。

![スクリーンショット 2022-11-28 午後5.39.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100460/21dbd44e-0acc-0d89-3b7b-430c02f47d4f.png)

簡単に図で整理するとこうなります。

- 検索
    - おすすめトピック
        - おすすめ（優先度高）
        - トレンド
        - ニュース
        - スポーツ
        - ...
    - 検索履歴
    - 検索結果
        - 話題のツイート（優先度高）
        - 最新
        - アカウント
        - 画像（優先度小）
        - ...

これがタブに紐付けられたコンテンツです。大分類・中分類・小分類でコンテンツを分けているということができます。そして、タブを表示したファーストビューで表示するかなどを考えながら優先度をつけていきます。

## 3. 不要なコンテンツを切り捨てる

そしてこの作業をすると必ずでてくるのが、「このコンテンツもユーザには必要だ！」といって、タブを6つにしたり、タブをやめてメインナビゲーションにハンバーガーメニューを採用するような「妥協」です。ただ、これは常にトレードオフを意識する必要があり、

__ユーザを迷子にさせてもコンテンツを追加する意味があるか__

を悩む必要があります。ついついAll in oneを考えがちですが、ユーザに価値がある機能が複数あるなら、文脈によってアプリを分割することも考えなければいけません。Facebookアプリが、Facebook Messagerを別アプリに分割したようにですね。

# ひとつの画面にコンテンツを詰め込む方法

そして最後に考えるのは、分類した項目をどうひとつの項目に詰め込むかです。いろいろな見せ方がありますので、まとめてみましょう。

## 1. Segment

![e7cc1e228b8e802208c5df069f576bab.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100460/c53bea9e-489b-af75-ad72-c9c47e71eab6.gif)

最も一般的な同じ画面にコンテンツを詰め込む方法でしょう。iOS、Androidでデザインは異なります。

```html
<ion-header>
  <ion-toolbar>
    <ion-segment [(ngModel)]="menuType" name="menuType" (ionChange)="changeMenu($event)">
      <ion-segment-button value="all">
        <div class="inner-ion-segment"><span>トーク</span></div>
      </ion-segment-button>
      <ion-segment-button value="favorite">
        <div class="inner-ion-segment"><span>お気に入り</span></div>
      </ion-segment-button>
    </ion-segment>
  </ion-toolbar>
</ion-header>
```

## 2. Radio Button

![d2d17b7ed91e64394fb60b75bc6b7cdd.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100460/0b97f10f-4a18-3a26-2ee9-fd9b36f90b4a.gif)

Segmentより小さなhintとなり、ユーザ操作を邪魔することはありません。反面、タップ後の動作が予期できないので、チュートリアルなどと組み合わせて使う必要があるでしょう。タイトルを動的に変えることで表示してる内容が変更されたことを通知します。

```html
<ion-header>
  <ion-toolbar>
    <ion-item lines="none" slot="start" class="toolbar-toggle">
      <ion-toggle mode="md" [(ngModel)]="isLikeOnly" (ionChange)="changeLikeOnly($any($event))"></ion-toggle>
    </ion-item>
    <ion-title>{{ currentAreaName }}</ion-title>
</ion-header>
```

## 3. Modal

![a294c9de1d76e3e176d82da1023b741b.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100460/07918606-d601-ebfc-b28c-68620a255c73.gif)

Headerに用意したButtonやFabButtonをアクションの起点にしてModalを表示します。コンテンツ投稿や絞り込みなどに利用することができます。

https://ionicframework.com/docs/ja/api/modal

## 4. Popover

![299ac543083506e7fded598656f94875.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100460/8b8dd279-8e4d-b2ef-6d1a-bb11587686c6.gif)

DOMをアクションの起点にして、Popoverを表示します。小さなヒントをだせる他、Popover内にbuttonを配置することによってナビゲーションを拡張するような使い方もできます。

https://ionicframework.com/docs/ja/api/popover

# まとめ

ファーストビューでコンテンツを表示しないもののメニュー名が表示されるという意味では、Segmentは優先度が高いものに利用することができるでしょう。またそういう意味ではラベルつきのButtonに紐ついたModalも同様ですね。
反面、Radio Buttonは優先度をある程度落としたコンテンツに便利ですし、アイコンだけのButtonに紐ついたModalはあくまでオプショナルの利用にするといいかと思います。

それではまた。