できるだけUI系のライブラリを用いないアニメーション
を盛り込んだサンプル実装まとめ
potatotips #45 @ リクルートマーケティングパートナーズ様
2017 / 11 / 28
Fumiya Sakai
自己紹介
・酒井 文也 (Fumiya Sakai)
・ever sense. inc エンジニア
・Designer → ServerSide Engineer → AppDeveloper
Accounts
・Facebook: https://www.facebook.com/fumiya.sakai.37
・Twitter: https://twitter.com/fumiyasac
・Github: https://github.com/fumiyasac
・Qiita: https://qiita.com/fumiyasac@github
Who are you?
Library (Personal)
Products (ever sense. inc)
このトピックスを選んだ理由
UI構築やアニメーション等の実装に携わる機会が多かった
こだわり1. 不自然にならない心地よいタイミングの動き
こだわり2. 動きの肝心なところはできる限りDIYする
こだわり3. 内部の構成も同様に気配りをする
参考資料とアプリ:
UIの中に随所に自然な形で散りばめられた心地の良いアニメーション
・AWA - 自然さを追求した本質体験のためのUX
https://www.slideshare.net/KokiTogashi/awa-coockpad-tech-kitchen-
20170913
今回はアプリ内の下記の2つの画面の動き
に近いものをDIYしてみました。
今回のサンプル概要
なるべくは1つのアプリに近づけたものになります。
・Githubサンプル
https://github.com/fumiyasac/InteractiveUISample
・詳細解説Qiita
https://qiita.com/fumiyasac@github/items/d1b56ffc6d7d46c0a616
設計のポイント
※ 画面はデモします
・データに関する処理とUI表示の処理をへの関係性
・なるべくView要素を部品に切り出す
・命名や処理の整理を行いやすくする準備を
【Chapter1】2つのコンテンツが切り替わるタブメニュー
UIScrollViewを活用するタブ&コンテンツの動きに関する設計
1番目のコンテンツ
(ContainerView)
(1) まずはタブ用とコンテンツ用のScrollViewを配置する。
<コンテンツ用ScrollViewのレイアウトを当てる手順>
2番目のコンテンツ
(ContainerView)
タブ用のScrollView コンテンツ用
ScrollView
(2) [Simulated Metrics] でFreeformを選び、[Simulated ViewController]
でサイズを750pxにする。
(3) ScrollViewの内部に、Widthを375px・Height=コンテンツ用ScrollView
の大きさのContainerViewを隣り合わせに2つ配置する。
(4) 1番目は上・左・下方向に0の制約を、2番目は上・右・下方向に0の制約
をそれぞれつける。
(5) ContainerViewからコンテンツ用のScrollViewへ [Ctrl + ドラッグ] して
Equal WidthとEqual Heightの制約をそれぞれつける
(6) [Simulated ViewController]をFixedへ戻す。
※ iPhone8の見た目の場合
【Chapter1】補足資料:制約の図解
・コンテンツ用のScrollViewをスワイプすると、動くバーと一緒に切替
・タブ用のScrollViewにあるボタンを押下後、0.26秒間のスライドをして切替
2つのScrollViewの動きについて
【Chapter2】UIScrollView & UIStackViewの構成
部品として切り出したUIViewの配置とAutoLayoutの制約に関するもの
(1) ContainerViewの高さをContainerViewにつな
がれているViewControllerのプロパティにする
UIStackViewを内包した
UIScrollView
<高さが可変するViewへの制約>
2番目のコンテンツ
(ContainerView)
高さが可変するView
高さが可変するView
+
セル高さが可変する
UITableViewを設置
Notificationを送信
して高さを調節する
height ≧ 0
priority = 1000
height = ●●
priority = 250
<StackView内のContainerViewへの制約>
UIView
UIView
ContainerView
(2) ViewControllerにNotificationを設定しておく
(3) viewDidLayoutSubviewsでtableViewの内部
コンテンツ高さとtableViewの高さを合わせる
(4) viewDidAppearでNotificationを送信する
【Chapter3】視差効果とCoreAnimationを組み合わせる
一覧表示部分のスクロールに合わせたアニメーションの効果を演出する
(1) UITableViewのスクロールに合わせてサムネイル画像がパララックスする
scrollViewDidScroll(_ scrollView: UIScrollView) でスクロール検知時に
セル側で設定したサムネイル画像の上下につけた制約を変更する。
利用するDelegate : UIScrollViewDelegate
<2つの性質の異なるアニメーション共存させる>
(2) スクロールでセルが現れる/消える際にフェードイン/アウトが入る
利用するDelegate : UITableViewDelegate
tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell,
forRowAt indexPath: IndexPath) でセルが表示されるタイミングになったら
「CoreAnimation」で設定したフェード処理を実行する。
【Chapter4】記事詳細を表示する想定の画面設計
ヘッダー上部のNavigationとアイキャッチ画像がスクロールに伴って動く
このViewControllerのポイント
(2) このViewControllerのrootに
UINavigationControllerを設置する
コンテンツ用表示
UITableView
NavigationBar
GradientHeaderView
ArticleHeaderView
ArticleHeaderViewは、
配置されたtableViewの
.headerにセットする
UITableView
(3) MainViewControllerから
ArticleViewControllerの画面遷移は、
ArticleCustomTransition.swiftを利用
※ 上の制約のみSuperview.Topにつけること
(1) UITableViewの制約:上下左右0
・GradientHeaderView
・ArticleHeaderView
ダミーのヘッダーになるView
スクロールで伸縮する画像のView
スクロール量に応じてArticleHeaderViewに配置した画像とGradientHeaderがアニメーションが行われる。
【Chapter4】補足資料:挙動に関するイメージ
動きの概要
y < 0 y > 0 ScrollViewDidScrollで制約を更新する
コードでConstraintを加えて、引数を
UIScrollViewとする、
「setParallaxEffectToHeaderView」
で制約を更新して動きを出す。
全体の流れと解説
(1) NavigationBarに内包するヘッダー
クラス名: GradientHeaderView.swift
(2) 画像を表示するヘッダー
クラス名: ArticleHeaderView.swift
記事を表示するために下へスクロールすると画像が隠れる
タイミングに合わせてNavigationBarが出現する。
y = 0
背景のアルファとダミーヘッダーの上方向の
制約を、
「setHeaderNavigationTopConstraint」
で更新して動きを出す。
【Chapter5】iPhoneXの画面に関する考慮
ヘッダーViewの高さをデバイスのサイズによってうまく調節する
端末の縦横サイズで場合分けを行う
デフォルトのNavigationBarと高さが
揃うように調節を加えると綺麗になる。
高さ調整を加える
(1) ヘッダーの高さ
クラス名: GradientHeaderView.swift
iPhoneX: 88.5, それ以外: 64.0
(2) 画像を表示するヘッダーの高さ
クラス名: ArticleHeaderView.swift
iPhoneX: 244, それ以外: 200
【補足1】Storyboard設計
【補足2】View - Model - PresenterパターンとUI
データとViewとの繋がりをできるだけパターン化して整理する
ViewController Presenter Model
データ構造の定義UI表示とデータ取得の仲介データを伴うUIの表示
API通信を伴う部分は、
SwiftyJSONを利用して初期化
→ データ構造の作成
※APIでの非同期通信
Alamofireをラッピングした
APIRequestManager.swiftを利用
(1) ViewController側で実行する
プロトコルの定義
(2) Modelの形に則ったデータの
作成やAPI通信のハンドリング
Presenter側で定義した
プロトコルの具体的な実装をする
データを取得 → UIの更新
の流れをつくる
Viewとデータの関係を密接にする
そのほかサンプルに盛り込んだトピックス
アプリUIに関する部分のDIYやカスタムトランジションを入れました
・View要素が多くなると整理がしずらくなる
パターン化やデータ&UIに関わる部分の
つなぎこみを上手にするための工夫を。
その1. 既存のUIKitの拡張を利用して効率化をする
その2. アコーディオン形式のUITableViewのToggle表現
その3. カスタムトランジションと3D表現の組み合わせ
その4. フォトギャラリーの用にUIScrollViewでの拡大縮小
・Storyboardが触りにくくなる
・定型処理の簡略化したい
作り込むとつらみになりがち
まとめ
ライブラリを使わないUI実装はなかなか味わいと興味がある部分
DIYをすることで見えてくるもの & 実務で活かすことができることが僕にはあった
UIの作り込みだけではなく設計や部品化する部分についても深掘りをしておく
※今回のサンプルで新しく追加した部分で気になる所は12/3の「Swift愛好会」のAdvent Calendarにて書きます
・Animationの組み合わせ(UIView.animateとCoreAnimation)で表現するワンポイント表現
・よくあるポピュラーそうなUIやライブラリの挙動をさらに深く知ることで得られた知識と知見
・データとの連携をするような局面ではできるだけ流れやパターンにしておくと後からの機能追加も楽になる
・最初にあらかたの設計や構成にあたりをつけておくと実際のUI構築が捗る印象
エバーセンスよりメッセージ
弊社ではiOS / Androidエンジニア募集しております!
https://www.wantedly.com/projects/158484

できるだけUI系のライブラリを用いないアニメーションを盛り込んだサンプル実装まとめ