ProgressHUDをどう置き換えるべきか

2024/05/20に公開

ProgressHUDの歴史

模倣されるHUD

現在でも、macOSではボリュームの変更時などに画面中央にHUDを表示します。

iPhoneはmacOSの延長線にあるため、古いiOSではボリュームの変更を同じようにHUDで表示していました。


https://stackoverflow.com/questions/48071333/hide-volume-hud-view-in-mpvolumeview

iOSの長い歴史の中では、Appleの作るUIをアプリ開発者が解釈・実装する文化が繰り返されており、このHUDも例外ではありませんでした。
アプリが行う処理の完了や失敗をグラフィカルに見せられるHUDは魅力的で、SVProgressHUDやMBProgressHUDといったUIライブラリが流行しました。

https://github.com/SVProgressHUD/SVProgressHUD

https://github.com/jdg/MBProgressHUD

"Progress"HUDの過ち

ProgressHUDと呼ばれるこのUIは、ローディング表示機能を持っており処理の完了だけでなく処理中の状態も表せるようになりました。
流行の裏側では、このローディング表示が開発者にとって非常に扱いやすかったと言う点も少なからずあります。
特に非同期処理は、処理中にユーザーが別の非同期処理を開始することを考慮したり、キャンセルや画面遷移など考えることが非常に多い処理です。
これをHUDで操作をブロックすることで開発の難易度は大きく下がります。

しかし、HUDで操作をブロックすることはユーザーにとっては体験を大きく損なう挙動です。
ユーザーが処理中に出来ることはローディングインジケータを眺めることだけになってしまったのです。
ProgressHUDが生み出したのは、非同期処理の同期化でした。

この過ちはAppleのfluid interfaceを始めとする、「ユーザーの意思決定はすぐに画面反映されるべき」と言う考えによって徐々に姿を減らすことになりました。

ProgressHUDをどう置き換えるべきか

では、これまでProgressHUDを使っていた部分をどのようなUIに置き換えるべきでしょうか?
いくつかのケーススタディを紹介します。

1.とにかく画面遷移をする

ProgressHUDでやりがちな処理として、次のようなフローがあります。

  1. ユーザーがボタンをタップする
  2. HUDを表示
  3. API通信を行い、遷移先の情報を取得する
  4. HUDを非表示
  5. 画面遷移

このフローでは、ユーザーがボタンをタップしてから画面遷移するまでの数秒間、アプリは操作を受け付けません。
このケースでは、次のように改善することができます。

  1. ユーザーがボタンをタップする
  2. 画面遷移
  3. 遷移後の画面の中で、情報を取得する
  4. 情報を表示

3では、遷移後の画面でプレースホルダやスケルトンローディングを使って取得中である事を表します。
こうすることで、遷移後の画面を閉じる事はいつでもユーザーの意思で行うことができます。

2.嘘で良いので画面に反映させる

次は、TwitterのようなSNSでいいねボタンを押した時の挙動を考えてみます。

  1. ユーザーがいいねボタンをタップする
  2. HUDを表示
  3. サーバーにいいねを押したことを書き込む
  4. HUDを非表示
  5. 星のマークを黄色に塗りつぶす

このフローでも、ユーザーがボタンをタップするたびにHUDが表示されてしまいます。特にいいねボタンは同じ話題のものを連続してタップするケースもあるため操作のテンポが悪くなります。
このケースでは次のように改善することができます。

  1. ユーザーがいいねボタンをタップする
  2. 星のマークを黄色に塗りつぶす
  3. サーバーにいいねを押したことを書き込む
  4. 成功すればそのまま、失敗したら星のマークを元に戻す

この改善案では、2の時点で画面に反映されており、追って失敗した場合だけ元に戻しています。
詳細な情報を表示する必要がないときは、アプリ側ではある程度それっぽい情報を出しておき、再読み込みなどの信頼できるデータ取得の後で本来の情報を表示することで十分なケースがあります。
必要に応じて、失敗したことを4の後で控えめに表示することも検討して良いでしょう。

3.ボタンの中でプログレスを表示する

2のような嘘がつけないケース、例えばヘッドホンとの接続を表すケースでは接続前に「接続済み」と表示することが憚られる場合があります。
このような場合でも、接続中HUDを出すのではなく接続ボタンの中にプログレスインジケーターを出すことが良いでしょう。
UIButtonには、progressを表示するAPIが存在するので活用しましょう。

let button = UIButton(configuration: .plain())
button.configuration?.showsActivityIndicator = true

また、Connectアプリではアラートのボタン内でプログレスしています。

4. アプリを閉じれるようにする

AIでの処理やファイルのアップロードなど、長い時間がかかる場合はHUDで進捗を出さずにライブアクティビティで進捗を出したり完了通知を出すなどして、待ち時間に別のアプリを操作できるようにします。

5. 課金・ポイント処理は1モーダル挟む

AppStoreでは購入処理中もキャンセル可能に設計されていますが、基本的には購入処理が反映されるまでは他の購入が出来ないようにモーダル内で決済が行われます。
Suicaのアプリは残高反映までに自由に操作する画面に遷移するため、間違えて2重に課金してしまうことがありました。このようなミスを引き起こすくらいであれば、実際のお金や換金性のあるポイントを増減する場合は、HUDによる操作制御を入れることも検討して良いかもしれません。

HUDは使ってはいけないのか

このように進捗やローディングをHUDで表示するのはバッドプラクティスですが、Appleは一貫してフィドバックをHUDで表示し続けています。
例えば、AppleMusicではお気に入りをするとHUDでその完了をフィードバックします。最近ではandroidのトースト風のミニマルなものに置き換わっており、控えめな表現になっています。
本来、HUDは画面を跨いでユーザーにフィードバックを行ったり、アテンションを取れる優れたUIです。利用シーンが適切か今一度考えて利用してみましょう。

Discussion