水無月の余韻 開発Sc.

プログラミング関連の雑記

iPadに最適化したビューにトライした

こんにちは。 加賀ゆびぬきシミュレータアプリのiOS版を、iPadで実行するときにより見やすいように改良しました。v1.3.4 大きな変更になったので、いくつかの気づきを記録します。

表示する情報量を増やしたい

加賀ゆびぬきシミュレータのiOS版は、およそ8割がiPhone、2割がiPadで利用されています。(2018年7月実績) 特別な対応をしていないiOSアプリは、iPadで表示したとき、iPhoneで表示しているものをそのまま引き伸ばしたように表示されます。

せっかく画面が大きいのにそれを活かせていないし、拡大されることで間抜けに見えてしまう画面もありました。

f:id:ichiko_revjune:20180909193640p:plain:w300
iPadで表示した場合 v1.3.3

ではどうするか。 単純に情報量を増やすためには、画面を分割して表示する項目を増やしていくことになります。 iPhoneで表示するときとまったく別の実装にはしたくなかったので、UISplitViewControllerを使って両環境での表示をひとつの実装で切り替えることを試しました。

画面分割による複雑さの上昇

f:id:ichiko_revjune:20180909193752p:plain:w300
iPadで表示した場合 v1.3.4

UISplitViewControllerを使うことで、ゆびぬき作成手順の一覧と管理をmasterView、各手順の詳細の表示と編集をdetailViewに表示できるようになりました。UISplitViewControllerの機能に任せることで、iPhoneでは1カラム、iPadでは2カラムの表示切り替えをやってくれます。

表示を切り替えて、中身をそろえていく過程では特に問題に気づきませんでした。しかし、編集機能を追加していったところ問題が見えてきました。

iPadで表示しているときには2カラム表示なので、手順の数を増減しつつ、同時に手順の中身を変更することが可能になります。これらが同時に操作可能であると、手順の中身を編集している最中にその手順を一覧から削除可能です。そうした操作によって不具合が生じやすくなりました。

階層構造を持つデータの親と子を同時に編集できることで、データの整合性を維持するためにロジックの工夫が必要になってしまったのです。

だいたい出来上がってからテストをする段階で、2つのデータ(親と子)の状況の組み合わせで、アプリの状態が決まることに気づき、想定するべき状況の多さに頭を抱えました。

最終的に、親データ(手順の一覧)の編集中には、子データ(手順の中身)の編集をできないようにすることで、アプリの状態を減らして対処しました。

UISplitViewControllerの代表的な使い方は、iOSの設定アプリでしょう。このアプリでは、データの親にあたる一覧(iPadで開いたときに左側に表示される部分)は追加は削除をユーザーが行うことはありません。 もともと想定されている使い方が設定アプリのようなものであれば、今回の加賀ゆびぬきシミュレータでの実装は、想定と違う使い方をしたことで複雑さが増してしまったのかと思います。

そもそも画面分割することで、ViewControllerが増えていくと、各ViewControllerごとにとりうる状態が増え、かつそれらの連携の組み合わせの考慮が必要になるようです。UISplitViewControllerでなかったとしても、画面分割することで、状態の複雑化は発生するので、複雑なアプリになっていくことは避けられないのでしょうか。

画面サイズへ対応して変化するレイアウト

iPhone/iPadの両方で使いやすい画面にするために、それぞれの状態でレイアウトが切り替わるようにしました。

iPhoneでは上部に製図を固定し、スライダーと手順の一覧がスクロール可能になっています。 iPadでは上部に製図とスライダーを固定で表示し、手順の一覧とその詳細がそれぞれ別にスクロール可能にしています。

f:id:ichiko_revjune:20180909193752p:plainf:id:ichiko_revjune:20180909193909p:plain
iPad/iPhoneで表示したときにレイアウトが切り替わる (v1.3.4)

レイアウトの切り替えは、一部はStoryboardで設定するのみで済ましました。SizeClassによって自動的にHideの有無を切り替えるよう指定しています。

当たり前なのかもしれませんが、初めは気づかなかったのが、各ViewControllerが受け取るSizeClassがそのVewControllerが扱うViewのみを対象に計測されているということです。アプリの実行されている画面サイズによるものと考えていたため、UISplitViewControllerの中に分割して表示されるViewControllerが受け取るサイズがRegularではなく、compactである理由がわかりませんでした。

製図とスライダーの表示の仕方を決める条件が、アプリが実行されている画面サイズであったため、ここは実装するしかありませんでした。ViewControllerに用意されている traitChange ??? をRootViewControllerに実装し、そこで受け取ったSizeClassを子ViewControllerへ伝播して、レイアウトを切り替えるようにしました。子ViewControllerが受け取るTraitCollectionとは別の値を使用するために、切り替えも自前で実装することにしました。

まとめ

これまでまともに扱ってこなかった、サイズクラスと画面分割をフル活用してアプリを改善してみました。

目的通りに表示する情報量を増やすことはできましたが、構造的に高い複雑性を抱え込んでしまうという結果になりました。 実際に、使い勝手が向上したかどうかはユーザーのみなさんの反応を待ちたいと思います。