日本のAppStoreでは未だ公開されていないfacebookの「Paper」ですが、
そのUIは実験的ながらも非常に高い完成度で個人的にはすごく好きなアプリです。
良いアプリがあれば "どうやって作っているのか" が気になるのがイチiOSエンジニアの性なんですが、facebook自体がPaperの裏側について説明した動画をしていて、非常に良い内容だったので紹介します。
なんのイベントなのかはよくわかってないのですが、
公開日は4/18なので比較的最近だと思います。
当然英語なので理解は浅いのですが、簡単にメモ。
First Impressions: Creating Contextually Aware Tutorials
- チュートリアルの価値
- 離脱(churn)を最小限にする
- ユーザーが新しい機能に気づけるようにする。
- ネガティブなレビューを減らす
- なぜチュートリアルは不快なのか
- 強制的である
- 利用前に表示される
- アプリ自体の体験と分離されている
- 目指すべきゴール
- (チュートリアル中全てを通して)邪魔にならないこと
- コンテキスト(文脈)にそっていること
- フィード・バックを与えること
- アプリ(の体験)の中に存在すること
- 非表示にできること
- 具体的にどんなチュートリアル仕様になっているかは動画の8:00頃から見られます。
- 学び
- 必要としている時のチュートリアルであればユーザは気に入ってくれる。
- "まず試してみる、必要であればマニュアルを参照する"
- (ユーザの)学習の強化とユーザをイライラさせてしまうことのトレードオフに気をつける。
Clean UI Code: Taming the Combinatorial Explosion
- 誤った考え
- UIコードは本質的に散らかってしまうものである
- UIコードをテストすることは不可能である。
- UIコードは頻繁に変更されリファクタリングの妨げになる。
- エンジニアリングの方針
- MVCモデルを尊重する
- 継承(inheritance)よりも集約(composition)を利用する
- 計算処理をアプリケーションから分離する。
- Model-View-Controller
- Model-View-Controller-ViewModel-Storeの5つのモデル
- ViewはModelではなくViewModelにのみ依存する。
- 集約と継承
- Paperでは多くのSotry(投稿)タイプを表示できる
- テキスト, 添付データ, フルスクリーン。。。
- Story Configuration
- Story Viewは以下の要素で構成される
- Story : View Model)から渡されたコンテンツ
- Metrics : 余白など座標空間上の情報。 C++の構造体)
- LayoutSpce : 各要素の
frame
を計算するクラス)
- Story Viewは以下の要素で構成される
Spring & Delight: Beyond Static Animations
- iOSのアニメーションでいかのことができたらどうだろうか?
- Velocity : アニメーションスピードの操作
- カスタムプロパティ
- カスタムアニメーション
- CALayerを使わないアニメーション
- 以上のことは
CAKeyframeAnimation
でできるかもしれないが利用しづらい。 - POPと呼ばれるアニメーションライブラリを作成した。
- POPの目指したもの
- より汎用的なアニメーションにフォーカスすること
- 拡張可能なフレームワークであること
- 開発者にとって利用しやすいものであること
- POPの機能
- 標準のイージング以外に
Spring
,Decay
とカスタムの3つを追加した。 - Core Animationのインターフェイス(
addAnimation:forKey:
など)と同じ要領で利用可能
- 標準のイージング以外に
- 近日中にPOPをオープンソースとして公開する。
Advanced Gestural Interactions: From Recognizers to Magic
- Part 1。 常にインタラクション可能なアプリの設計
- インタラクションのブロックはユーザーにとって不快である。
- Photos(カメラロール)などでは実際にインタラクション可能なように作られている
- インタラプション(アニメーションの中止処理)を入れる
- ジェスチャの検出時にアニメーションを
remove
する。
- ジェスチャの検出時にアニメーションを
- Pro-Tips
frame
操作を避けbounds
とposition
を利用する。setFrame
を呼び出すとアニメーション中のtransform
情報が消えてしまう。
- ダブルタップジェスチャーを利用しない
- シングルタップジェスチャーの検出に時間がかかるようになるので。
- Part 2。 ジェスチャーとアニメーションのギャップを埋める
- ジェスチャーからアニメーションに映るときのアニメーション速度にギャップを作らない
UIPanGestureRecognizer#velocityInView:
を利用する。
- ジェスチャーからアニメーションに映るときのアニメーション速度にギャップを作らない
- Part 3。 ピンチ, パン, ローテーションジェスチャを同時に検出する。
- レコグナイザーの値は相対値として利用する。
- ジェスチャーが始まった時の
transform
値をベース値として保存しておく。 - ベース値とレコグナイザーの値を合成してアニメーションに適用する。
Building Asynchronous User Interfaces: Keeping Gestures & Animations Smooth
- (アニメーションの)ドロップフレーム(=フレーム落ち)は、ユーザーを苛つかせる。
- タッチ処理もアニメーションも60FPSで実行されなければならない。
- iOS 7のアニメーション処理はこれまでとどう変わったか?
- 個々のジェスチャーや静的アニメーションはメインスレッドの処理落ちを起こさなかった。
- 連続したジェスチャーや動的アニメーションが(以前は)行えなかった。
- CoreAnimationのレンダリングサーバーは静的アニメーションにのみ効率化されていた。
- 新しいインタラクションは現在もまだ実装中である(完成度が低い)
- OSのスケジューラーはもはやなめらかなアニメーションを維持できない。
- どの処理がドロップフレームを引き起こすのか?
- メインスレッド上で5ms以上かかる処理が発生すると起きる
- 時間のかかる処理の例
- テキストのサイジングを行うときの
-layoutSubviews
/-layoutSublayers
-drawRect:
(テキスト, 画像, グラフィック関係なく)- UIViewの
init
/addSubView
/removeFromSuperview
/dealloc
- テキストのサイジングを行うときの
- 最適化は常に重要だが、アプリ全体を通してメインスレッドをブロックしないようにする必要があるのであれば、アプリ自体の構造的な解決が必要になるため、最適化すればいいというものではない。
- プラットフォーム自体の制約
- UIKitとCore Animationの多くのクラスはスレッドセーフではない。
- メインスレッド以外での
UIView
/CALayer
の配置はクラッシュを引き起こす。 UIWebView
,UITextView
などシステム的にクリティカルなクラスが多く存在する。- 故に、UIKitからの分離ではなくUIKitへの統合というアプローチが必要になる。
- Paperでの解決策
- スレッドセーフな
node
オブジェクトを生成して管理させる。
- スレッドセーフな
node
オブジェクト- UIをリフレッシュする際にはルートビューのノードでレイアウト処理を実行する。(サブスレッド)
- Core Animationでは
-display
メソッドが呼ばれるので、そのタイミングでメインスレッドで描画を行う。
- オブジェクトのコンポジションを並列に行う。
- iOSデバイスの80%はデュアルコアなので意味がある。
- テキストのサイジングやレンダリングといった再帰的な処理は効果が高い。
正直後半の方はだいぶ深い話なので、恥ずかしながら殆どわかってません。ぜひ実際に動画を見て下さい。
個人的には一番最初のチュートリアルについての話が興味深かったです。
作り手としてはユーザーによりアプリを理解してもらいたくてチュートリアルを作るのですが、
ユーザーは別にチュートリアルなんで見たくもないんですよね。なので必要なときに必要な分だけ、かついつでもチュートリアルを止められるような仕組みにしないとダメだよという話だったわけですが、こうやって設計方針を示してくれると非常に助かります。
イベントの最後はQ&Aになってますが、プロジェクトの進め方やテスト手法などが多かったと思います。このへんは日本もアメリカも変わらない気がします(笑)
というわけでタイトルはちょっと釣りっぽく書きましたが、とても参考になる動画なのでぜひ観てください。