その Dialog は本当に必要ですか？

ダイアログは、ユーザとの対話の中でも特に「確認」や「注意」を促すために用いられる UI コンポーネントの一つです。二択あるいは三択の項目を配置して、YES/NO や OK/Cancel などのインタラクションを用意することで、ユーザとの対話をすることが出来ます。あるいは、単に現在の状態を表示（読込中など）し、その他の各種操作をブロックすることで、待つ必要が有ることを明示することも出来ます。

一方で、ダイアログはその表示が画面の前面に大きく表示され、時にダイアログ以外へのインタラクションを禁じる場合もあることから、使いどころを間違うと非常に鬱陶しく見えるものでもあります。また、ダイアログのキャンセル操作が出来ない場合において、いつまでもダイアログが出続けてしまうとユーザの負担は大きくなります。

この記事では、ダイアログを使用している場面において、その他の表現方法や実装の工夫を使うことができるかどうかを考えていきます。

# プラットフォームのガイドライン

Android、iOS ともにガイドラインがあります。ダイアログの中でも特に、モーダルと言うと iOS の文化が強いように思いますが、実のところ Android でもモーダルのような UI は作ることが出来ます。ただし、iOS も Android もモーダルに関しては極力ユーザの邪魔にならないような配慮をすべきという言及が見られます。

## モーダルに関するガイドライン

少なくとも、ひたすら読込中の表示を表示し続け、かつ前の画面に戻るようなインタラクションをブロックするモーダルは避けるようなガイドラインがあるようです。

- Android
  - https://youtu.be/pEGWcMTxs3I (英語)
  - https://youtu.be/x_gxZd9kLv4 (日本語)
  - `Modal loading dialogs are aweful`
- iOS
  - https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/MobileHIG/Modal.html
  - `Always provide an obvious and safe way to exit a modal task`

以降ではモーダル以外にどのような表現方法があるかを探っていきますが、どうしてもモーダルに頼らざるをえない場面も出てきます。そういった場合でも、上記のガイドラインをもとにしたモーダルの使い方をしていきたいものです。

# よくある事例

ここからはよく見かける事例を元に、どのような代替手段があるかを見ていきます。

## 確認ダイアログ

YES/NO や OK/Cancel といった選択肢を表示し、本当にその操作を実行してよいかどうかを確認するダイアログです。

### 後戻りできない操作の確認

例えば、何かしらのデータを削除する操作をした時に、本当に削除してよいかどうかをユーザに確認するためのダイアログ、と言った類のものです。

取り返しがつかない操作ですから、ユーザへの確認は必ずしておきたいですが、最近はダイアログを使う以外の方法がとれるようになっています。

#### 1. SnackBar

最近 Android に導入された、Toast のような使い方ができるものです。削除操作の結果報告と、キャンセル操作をするためのボタンを配置することが出来、このキャンセル操作のボタンをタップすることで、削除がキャンセルされます。

![snackbar.png](https://qiita-image-store.s3.amazonaws.com/0/31829/d4bccb7f-6678-11b9-95b5-17a13b0ee577.png)

ただし、SnackBar は一定時間経過すると消滅してしまうので、あまりにその表示時間が短すぎるのも良くないかもしれません（表示時間は調整が可能です）。

#### 2. Swipe ListView

Gmail が取り入れているような UI です。スワイプ操作で削除をすると、削除したアイテムの場所に「削除しました」というメッセージと「元に戻す」というボタンが表示されます。「元に戻す」ボタンをタップすることによって、削除がキャンセルされます。

![swipelistview.png](https://qiita-image-store.s3.amazonaws.com/0/31829/bbb49097-b91b-e25f-1570-ae6fcc432cc9.png)

ただし、ListView や CollectionView の操作によって「元に戻す」ボタンが消えてしまうため、さくさく横スワイプしてさくさく縦スワイプしていると、もはや元に戻すボタンは一瞬にして消滅してしまい、あまり役に立たなくなってしまいます。

#### 3. ツーステップ

（正式な名前がよくわからないので、分かる人がいたらご指摘くださいmm）
iOS 6 のミュージックアプリ等で使われている UI です。リストの編集中に停止マークをタップしないと削除ボタンが表示されないようにすることで、うっかり操作もある程度防いでいます。かつ、停止マークをタップした時点で削除の意思がある程度見えるので、敢えてダイアログを表示していません。

<img width="320" alt="two_step_confirm.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/31829/3ab9200f-945e-fea9-289f-94967c427413.png">

### キャンセルをキャンセルする

どちらかと言うと言葉の問題のようにも思いますが、何かの操作をキャンセルする時のダイアログの選択肢に、OK/Cancel が並んでいるとこうなります。

「xxx をキャンセルしますか？」「OK/Cancel」

実に微妙なダイアログが出来上がってしまいます。

#### 他のワーディング

確認したいことは、「xxx をするかどうか」ですから、「xxx をする」「xxx をしない」という選択肢を提示するという方法でも良いでしょう。或いはシンプルに、選択肢をYES/NOに限ることも良いでしょう。

#### そもそもダイアログを出さない

潔く(?)取りやめる操作が実行されたことを表示するだけに留める方法もあるでしょう。あるいは、手軽にやり直しが聞くものもまた、ダイアログで再確認する必要性も薄くなります。

![取り消し操作を行っても確認ダイアログはない](https://qiita-image-store.s3.amazonaws.com/0/31829/521c3bac-3c6e-4a2a-31b8-1b4676e209f4.png)

### アプリの終了を確認する

ゲーム中や、ドキュメントの編集中だったり、写真を加工中に保存しないままだったり、大事な情報を入力中だったりするときにアプリを終了するような場合を除いて、アプリを終了する際に「終了しますか？」のダイアログは出さないようにするのが大前提です。

その上で、仮に大事な情報が保存されないまま終了（前の画面に戻ろうとすること）しようとしても安心安全に終了できるような作りにしておく、というのもアプリを作る上で大事だと思います。

#### 定期的に自動保存する

保存という操作を自動でやってくれると、うっかり操作で終了してしまっても、次に起動した時に元の状態に復帰できます。

これならば、仮にプロセスごと殺されてもある程度データが復帰できます。

ただ、うっかり終了してしまった時のために、自動で保存したことを Toast などで通知しておくとより親切なアプリになると思います。

### 入力のエラーを通知する

特に文字列を入力するようなものの場合、どんな文字列が入力可能か等のバリデーションが発生します。

すべての入力が終わってユーザのアクションが発生したタイミングでバリデーションを行うことは大事なことですが、入力に何らかのエラーが有ることは、ユーザのアクションよりも前に通知してあげることも可能です。

#### EditText 等の仕組みを活用する

EditText にはエラーを表示する仕組みがあります。また、Material Design のガイドラインにおいては、EditText で入力可能な文字列についての説明やエラーの表示に関するガイドラインが定められており、ライブラリで簡単に実装できるようになっています。これによりダイアログでエラーを通知するよりも早くユーザがエラーに気付くことが出来ます。

![edittext.png](https://qiita-image-store.s3.amazonaws.com/0/31829/6dd60f1f-eccb-20c8-f5ca-6e4f5c114300.png)

最終的にアクションを起こした後にエラーが検知された場合も、Toast や SnackBar 等の方法が取れることも有るでしょう。

## 進捗の表示

ネットワークを介して通信を行うアプリでは、そこかしこでユーザに通信の完了を待ってもらう場面が出てきます。そうなった時に、現在の処理がどこまで進んでいるのか、あるいは、処理中であるということをユーザに伝える手段として、進捗をダイアログに表示することが多々あります。

が、ここでモーダルなダイアログには一つの課題が生まれます。それは、ダイアログが邪魔で他の UI を操作できなくなることです。特に Android の場合、戻るボタンすらも利かなくなるような設定が可能です。

### ListView や CollectionView の場合

#### List 表示の代替として

List にコンテンツがない状態の時に、読込みの状態を表示するようにすることで、モーダルを回避できます。

#### 引っ張り更新、もっと読むのプログレス

List のヘッダやフッタに View を追加し、その View にプログレスを表示することで、モーダルを回避できます。

#### ActionBar や NavigationController の下にプログレス表示

Chrome 等で用いられるようなプログレスの出し方、あるいは、最近の Android のガイドラインのように円型のプログレスを引っ張って表示するなどでモーダルを回避できます。

### データのアップロードの場合

データのアップロードも時間のかかる処理として、進捗を表示すべきもののひとつです。が、完了するまで全てがモーダルやダイアログによってブロックされるのは使い勝手が悪くなります。

#### 通知を活用する

データのアップロードに際してアプリがフォアグラウンドにいる必要が無い場合、通知に進捗を表示することで、モーダルを回避できます。

#### ボタンに進捗を表示する

ログインボタンや、設定の保存ボタン等、どうしてもアプリがフォアグラウンドにいる必要がある場合の手段として、ボタンに進捗を表示してしまうことで、モーダルを回避できます。

- [Android Progress Button](https://github.com/dmytrodanylyk/android-process-button)
- [Progress Layout](https://github.com/iammert/ProgressLayout)
- [FAB Progress Circle](https://github.com/JorgeCastilloPrz/FABProgressCircle)

# まとめ

ダイアログは便利ですが、注意しないとアプリの使いづらさを演出してしまいます。現在では様々な表現でもってダイアログではない選択肢の提示方法が提案されてきていますので、本当に必要な場面でのみダイアログが活用できるような道を模索していきたいですね。