Monthly Archives: December 2015

エレベーターのボタンについて

UI理論101問題: このボタンは全て無くすことができますが、ひとつだけ残すとしたらどれでしょうか? pic.twitter.com/UFcG2h4PE8 — Manabu Ueno (@manabuueno) 2015, 12月 18 このツイートが意外にもたくさんRTされていたので、解説してみる。 UI設計理論としてはまず、「目的達成までのユーザーの運動と認知の負荷を減らす」という考え方をするのが基本だ。同じ結果を得るためなら、操作や選択肢は少ない方がよい。UIはユーザーにとってオッカムの剃刀であることが望ましい。 ただしシステムを利用して目的を達成するプロセスには「テスラーの複雑性保存の法則」というものがあり、入力しなければいけない情報を一定以上減らすことはできない。 一般的なエレベーターを利用する上で必要となる最低限のインプットは、次の6つだろう。 エレベーターを呼ぶ合図 乗るためにドアを開ける合図 乗った後にドアを閉める合図 行き先階 出発の合図 到着した際にドアを開ける合図 テスラーは、複雑性は減らせないが移動はできると言っている。必要なインプットの負担をユーザー側からシステム側に移動することで、ユーザーにとっての労力を減らすことができる。 一般的なエレベーターにおいては、上記の6つのうち、2, 3, 5, 6 については適当なタイミングで自動的に行われるようになっているので、ユーザーが行うのは 1 と 4 だけである。1 はエレベーター外の上下ボタン、3 はエレベーター内の階数ボタンを使ってユーザーがインプットする。 これらはユーザーが特定の階に移動するために必要な操作だが、実際にはこれらに加えて、自動化された動作をキャンセルする機能があるのが普通だ。すなわち次の2つ。 ドアが閉じようとするのをキャンセルする合図 一定時間を待たずにすぐにドアを閉じる合図 7 は開くボタン、8 は閉じるボタンで行われる。開くボタンについてはスプリング式になっていて、押し続けている間その合図が継続する。また開くボタンは、エレベーターが移動している最中には安全のためにディスエーブルになっている。ふたつ以上の合図が同時に発せられた場合は、安全な方に寄せて他は無視される。 開くボタンは、自動的に閉まろうとするドアに(自分を含めた)誰かが挟まれないよう、エレベーター内の人が押すためのもので、安全のためのスイッチだ。一方、閉じるボタンは、急いでいる人が早くエレベーターを出発させたい場合にのみ使うものであるため、重要度は低い。閉じるボタンが無いエレベーターも存在する。 またドアには通常、安全装置があり、物が挟まるとドアが開くようになっている。これに加えて、赤外線センサーによってドアに物が接触するのを防ぐ機能を備えているものも増えている。 エレベーターのボタンの押し間違いで一番問題になるのは、「ドアを開こうとして間違って閉じてしまう」時である。なぜなら、安全のためにとった行為が、かえって危険な状況を作ってしまうからだ。このリスクを考えると、閉じるボタンの存在はかなり問題だろう。閉じるボタンが無いエレベーターではこの問題は発生しない。ボタンがふたつ並んでいれば必ず押し間違いが起こるが、ひとつなら起こらないからだ。 閉じるボタンの無いエレベーターでは、階数ボタンを押すとすぐにドアが閉まるようになっていたり、階数ボタンの長押しでドアが閉まるようになっていたりするのを 見たことがある。これらは、行き先を指定する行為=出発の意思という解釈をしているのであり、複雑性の移動方針としては理にかなっていると思った。またこれらはいずれもセンサーつきであったため、閉まろうとするドアに挟まってしまうこともなかった。 つまりドア自体に備わっている安全装置がうまく機能するなら、7 と 8 は自動化されるので、開くボタンも閉じるボタンも理論上は不要になる。 銀座 Apple Store のエレベーターには行き先階ボタンも開閉ボタンもなく、自動的に全階に止まりながらシャトル運行し続ける。当然センサーによる安全装置が働いている。 さて、今回のエレベーターだが、駅によくあるタイプのもので、写真で分かるとおり、ふたつの階を行き来するだけのものだ。つまりユーザーの行き先は常にひとつしかない。現在ユーザーがとれる操作がひとつしかないなら、その操作は自動化できる。現在有効な選択肢がひとつしかないなら、オッカムの剃刀として、その選択行為は省略できる。 だから8つのインプットのうち、4 もシステム側に移動でき、写真にあるボタンは全て無くすことができる。 ここで、ボタンがなくなったエレベーターの動きを想像してみる。 […]

タッチジェスチャとコンストレイント

iOS には、あらかじめいくつかのタッチジェスチャを認識する API が用意されている。 ジェスチャとは、プリミティブな入力イベントの特定の組み合わせをひとつの意味として扱うものだ。例えばパソコンであれば、マウスボタンの押し下げ(マウスダウン)やそれを放すこと(マウスアップ)がプリミティブな入力イベントの例であり、このふたつを連続して一定面積内で行うと、クリックというジェスチャになる。一般的なマウスのジェスチャには他にも、ムーブ、ダブルクリック、ドラッグなどがある。 タッチデバイスではマウスのかわりにタッチイベントが用いられるが、プリミティブな入力としては、例えばタッチの開始や終了がある。指をスクリーンに触れて、それを一定面積内で放すと、タップというジェスチャになる。 iOS では、基本的なジェスチャとして次の7種類が想定されており、これらの動作を検出する API が用意されている。 タップ ピンチ ローテーション スワイプ パン スクリーンエッジパン ロングプレス それぞれには更に、指の本数や、動作の段階(ジェスチャが開始された、継続中、終了した)ごとに処理を変える仕組みが含まれている。 つまりタッチジェスチャは、マウスのジェスチャに比べて、バリエーションが多い。 バリエーションが多いと言っても、例えばダブルクリックがシングルクリックの二連続でできているように、ジェスチャによっては他のジェスチャの組み合わせでできているものもある。例えばスワイプジェスチャは、水平もしくは垂直方向に、一定以上のスピードでパンすることを意味している。 別な言い方をすれば、ある指の動作が、AのジェスチャなのかBのジェスチャなのかという判定は、マウスの場合に比べて、かなり微妙なものになっている。 また、同一画面上で同じ種類のジェスチャが複数の意味で実装されていることも多い。例えば iOS 9 のホーム画面では、水平方向のパンはアイコン一覧のページめくり、下方向へのパンは検索窓の表示、画面下辺付近からの上方向パンはコントロールセンターの表示、画面上部付近から下方向のパンは通知センターの表示、というふうに、いくつものパンジェスチャが実装されている。 複数のジェスチャを同一画面上に実装する場合は、通常、ジェスチャ同士に優先度をつけて、あるジェスチャが発動したら他のジェスチャはキャンセルされるようになっている。ホーム画面の例であれば、下方向へのパン操作が行われた時、それが画面上辺付近から開始されていれば、通知センター表示が優先され、検索ボックス表示の処理はキャンセルされる。 ジェスチャのバリエーションが複雑な分、こういった優先度づけやキャンセル条件などの処理は非常に入り組んだものになりがちだ。操作の示唆が暗黙的な分、ユーザーはうまく操作できないこともあるだろう。 Apple Watch のデジタルタッチ Apple Watch では、サイドボタンからフレンドを選んでデジタルタッチと呼ばれる特殊なメッセージを送信することができる。 デジタルタッチには三種類のモードがある。スケッチ、タップ、ハートビートだ。スケッチは指で線画を描くもの。タップはスクリーンをトントンと叩くもの。ハートビートは現在の心拍をモニターする。 これらのデジタルタッチは、リアルタイムに相手のウォッチ画面に表示される。タッチデバイスならではの非言語的なインスタントコミュニケーションだ。 デジタルタッチによるやりとりが実際に面白いかは置いておいて、その仕様はよくデザインされていると思う。 Apple Watch ではデザインガイドラインとして、ユーザーに複雑なことはさせるなと謳っている。デジタルタッチを送る時にも、送信ボタンを押したりモード変更の操作をする必要はない。 どのようにモードが決定されるのかというと、指でスクリーンをなぞる(パンジェスチャ)とスケッチモード、指でスクリーンを軽く叩くと(タップジェスチャ)タップモード、二本指でスクリーンを押さえつけると(二本指ロングプレス)ハートビートのモードになる。 このように事前の手続きなしでモードが作られるところがよい。三つが異なるジェスチャなので、判定が混乱せずに済むようになっている。 モードの決定はメッセージを作成する動作と自然に対応しているので、モードレスモードとなっている。 中でもハートビートは秀逸だ。 ハートビートは現在の心拍を継続的に相手に送りつづけるものだから、開始と継続と終了の合図をひとつの動作で行えるように、長押しのジェスチャーを用いるのは自然だ。また、センサーが正しく心拍をモニターするにはウォッチ本体を手首に密着させる必要があるが、二本指でスクリーンを押すという動作がそれを助けている。これがもし一本指だと、パンやタップのジェスチャと誤判定してしまったり、モニタリングに失敗するかもしれない。二本指の長押しという特徴的な動作が他のジェスチャとの明確な区別となっていて、はじめは学習が必要だが、ユーザーにとってのジェスチャの発動させやすさ、システムにとっての判定のしやすさ、そして心拍モニタリングを正確にするための「コンストレイント」になっている。 コンストレイントとは、デザインにおける制限のこと。ユーザーの行動を意図的に制限することで、誤操作を減らしたり有効な使い方を促したりするテクニックだ。 例えば、昔の自動車ではイグニッションキーとエンジンスタートのボタンが別々になっていたという。それだとキーを挿し忘れたままエンジンボタンを押すという操作ミスが起こる。イグニッションキーを刺さなければエンジンスタートの合図が出せないようデザインに制限を持たせることで、問題がなくなった。ユーザーにしてみればキーを使うこととエンジンを動かすことは目的が一致しているので、制約は自然なものとなり、行動が抑制されたような窮屈さは感じない。むしろ合理的であたりまえのデザインだと感じる。 タッチジェスチャは暗黙的でありかつ誤判定しやすいものだが、Apple Watch のデジタルタッチはそれをうまく扱っている。

UITextView のタッチジェスチャと Textwell

UITextView のバグと対策 iOS 7 より UITextView の挙動が著しくおかしいということについて「iOS 7 のテキスト入力欄(UITextView)の問題について」に書いた。iOS 8 においても UITextView のバグは直されなかった。 iOS 9 が発表され、SDK をいじってみて、なんとなく直っているような気がしたが、それは気のせいだった。全体的には少しずつ改善されているように思うが、依然として振る舞いが安定しない。特に、カーソルがスクロール外の位置にある時に、ビューをカーソルが表示されるところまでスクロールさせるメソッドがうまく機能しないので、カーソルを見失ったような状態になりますい。この現象は純正アプリも含めて、UITextView を使った色々な箇所で見受けられる。 私がプロダクトマネージャーをつとめる Textwell の iOS 版では、UITextView のバグを回避するための補正処理として、具体的に、以下のメソッド/プロパティをオーバーライドしている。 ・scrollRangeToVisible: カーソルが見える位置までビューをスクロールするメソッドだが、テキストレンジの座標が正しく計算されていないようなので、自前でそれを計算し直し、”scrollRectToVisible:animated:” に投げる。 ・closestPositionToPoint: 特定の座標に一番近いテキストポジションを返すメソッド。タッチジェスチャとテキスト処理の橋渡しをする重要なメソッドだが、時々おかしな値を返してくるので、レイアウトマネージャーのグリフ情報を使って正しいポジションを返すようにする。 ・layoutManager.allowsNonContiguousLayout デフォルトでは NO だがこれを YES にする。 ・layoutManager.hyphenationFactor デフォルトで 0 のはずだが、何かの拍子に値が変わるのかもしれない。0 に指定し直すと挙動がましになる気がする。 これらを行うことで、概ね iOS 6 までの UITextView と同じ挙動になる。 Textwell v1.4 までのジェスチャ ここから本題。 iOS 9 をターゲットにリリースした Textwell v1.5 […]