15
指の動きや遷移時等のアニメーションを 生かしたUIのサンプル解説 Swiftビギナーズ勉強会 #21 2017/02/18 Fumiya Sakai

指の動きや遷移時等のアニメーションを生かしたUIのサンプル解説

Embed Size (px)

Citation preview

Page 1: 指の動きや遷移時等のアニメーションを生かしたUIのサンプル解説

指の動きや遷移時等のアニメーションを

生かしたUIのサンプル解説

Swiftビギナーズ勉強会#21

2017/02/18FumiyaSakai

Page 2: 指の動きや遷移時等のアニメーションを生かしたUIのサンプル解説

自己紹介と簡単な経歴など

✦ 今までの仕事履歴(本業)

石川県金沢市生まれ

本業はサーバーサイドのプログラマ※Rails&PHP使い

26歳〜32歳: Webプログラマ(PHP&Rubyがキャリア長い)

23歳〜25歳: Webデザイナー兼ディレクター

2017年3月よりiOSアプリ開発のエンジニアになります。

趣味:シルバーアクセサリー集め・スイーツ作り・アプリ開発

女子向け・グルメ・エンタメ関連のお仕事が多い

Qiita:http://qiita.com/fumiyasac@github

Github:https://github.com/fumiyasac

✦ 酒井文也(さかいふみや)

東京(大塚)住まいの32歳

こんな格好を普段からしているので遊び人に見られますがエンジニアです。

文系卒に思われますが実は数学科で理系卒です。

めっちゃお酒好きそうに見えますがビール苦手でお酒も超弱いです。

今でもたまにUIまわりとか触りたくなることがあったりなかったり

今年の4月からフリーランスです。(割とお堅い感じの会社にいます)

最近のはまっている食べ物はカボチャと担々麺と甘栗です。

最近はSwift以外ではRailsやLaravel・CakePHP・Node.jsなんかも

Page 3: 指の動きや遷移時等のアニメーションを生かしたUIのサンプル解説

これまでに作ったもの(ネイティブアプリ)

①簡易家計簿アプリ「Coffre」

②ゲームアプリ「10秒虫食い算」

・カレンダーを自作しています

・シンプルなお小遣い帳感覚で支出管理できます

・全問正解者ほとんどいません…

・不定期ですがコラムも書いています

・サーバーサイドはRubyonRailsを使用

http://www.coffre.me/

・デザインにもこだわってみました(特にグラフ)

・実はちょっとバグがあります。

・問題は今後追加予定(現在110問収録)

個人的にはなりますが、他にもアプリ・Webサービスなど開発中です(2016年も宜しくお願いします)

・サイト等は次回のアップデートで公開予定

http://blog.just1factory.net/services/284

・若干の中毒性を含みます

Page 4: 指の動きや遷移時等のアニメーションを生かしたUIのサンプル解説

カレンダーが好きでライブラリを作りました

日本の祝祭日を計算で出してくれる

・カレンダーアプリ等での活用を想定

・シルバーウィーク・ゴールデンウィークも対応

・ハッピーマンデー法の施行も対応

・春分の日・秋分の日にも対応

・過去の祝祭日もおおむね考慮はしている

構想や基本実装は僕ですが、他に4名のContributorのお力添えがあり実運用できるレベルになりました!

職人の手作業で計算しております!

・HTTP(HTTPS)通信は不要

★CalculateCalendarLogicver0.1.3

【最新情報】最近はmacOSのサポートがされました!※CocoaPods/Carthage経由で導入できます。

・Github:https://github.com/fumiyasac/handMadeCalendarAdvance

・実装解説:http://qiita.com/fumiyasac@github/items/33bfc07ad36dfffcdf8f

【2017年】Swift3系への正式対応をしていますので是非README等を参考に導入してみてください!

Page 5: 指の動きや遷移時等のアニメーションを生かしたUIのサンプル解説

✦ 今回はできるだけ1つのアプリに近しい形になるようにしました

今回紹介するUIサンプルの概略図

食べたいもしくは作ってみたいレシピをアーカイブするアプリのUIに指の動きや遷移を工夫してみました。

Page 6: 指の動きや遷移時等のアニメーションを生かしたUIのサンプル解説

✦ UI部分はライブラリなしでAPI通信時等の場面でライブラリを活用

使用したライブラリやサンプルについて

今回はコードを深掘りするよりも実装を行う前段階の設計やUIに絡む部分の実装ポイントをピックアップ。

★使用ライブラリの紹介

★今回の紹介する解説記事やGithubのサンプルについて

(Qiita)

ジェスチャーやカスタムトランジションを利用して入力時やコンテンツ表示時に一工夫を加えたUIの

実装ポイントまとめ

http://qiita.com/fumiyasac@github/items/6c4c2b909a821932be04

(Github)DraggableImageForm

https://github.com/fumiyasac/DraggableImageForm

ライブラリ名 ライブラリの機能概要

RealmSwift アプリ内のデータベース

SwiftyJSON JSONデータの解析をしやすくする

Alamofire HTTPないしはHTTPSのネットワーク通信用

KingFisher 画像URLからの非同期での画像表示とキャッシュサポート

CalculateCalendarLogic 日本の祝祭日の判定

Page 7: 指の動きや遷移時等のアニメーションを生かしたUIのサンプル解説

✦ 画面や機能の役割に応じてStoryboardファイルの分割をしました

このサンプルの画面遷移とStoryboard

Storyboardファイルを分割することでチーム開発のconflict防止や機能毎の画面見通しを良くする効果も。

MakeRecipeController.swift ArchiveRecipeController.swift

AddController.swift GalleryController.swift GalleryDetailController.swift

Main.storyboard

(レシピアーカイブ作成) (レシピアーカイブ一覧)

(選択レシピ一覧) (選択レシピ詳細)

画面遷移時 CustomTransition.swift

(レシピアーカイブ追加)

Add.storyboard Gallery.storyboard

ViewController.swift

サイドメニュー&メインコンテンツ

(2つのContainerView)

Navigation Controller

Page 8: 指の動きや遷移時等のアニメーションを生かしたUIのサンプル解説

✦ Alamofireの通信を司る部分を間に基底となる構造体をはさむ

APIとの通信を行う部分の実装

APIへのアクセス処理部分をAPIManager.swiftで管理をすることでControllerではパラメータを渡すだけに。

★Alamofireでの通信部分(APIからのデータ取得時)は下記のような構成

APIManager.swift

楽天レシピAPIからのデータ取得

(Alamofireを利用したデータ取得)MakeRecipeController.swift

Struct

実際の処理に関して:loadApiData(categoryId: String) { … } メソッドに処理の実体が記載されている。 ※ SwifyJSONでのJSONパースとUICollectionView表示用データ整形 ※ UICollectionViewのUserInteractionの制御も含む

CategoryList.swift(パラメータ用の大カテゴリ定義)

設定パラメータ一覧:

format:String

applicationId:String

categoryId:String

(レスポンス形式「json」)

(楽天WebサービスのAPIキー)

(大カテゴリのID)

Struct

使用している外部API:

楽天レシピカテゴリ別ランキングAPI

大カテゴリに該当するレシピデータを4件取得する

※このサンプルではデータ取得は「Add」ボタンがトリガー

Page 9: 指の動きや遷移時等のアニメーションを生かしたUIのサンプル解説

✦ 1つのアーカイブデータに対してレシピのデータが多数紐づく形

レシピデータの保存方法とテーブル定義

プライマリキーの設定ができるのでデータ構造の見通しが良い(CoreDataはこの関連付けは暗黙的に行う)

★今回はRealmを使用してデータの保存・表示・削除を行っています

Many

Recipe.swift

Archive.swift

カラム名一覧:

id:Int

archive_id:Int

rakuten_id:String

rakuten_indication:String

rakuten_published:String

rakuten_image:String

rakuten_url:String

(このテーブルの一意ID)

(Archive.swiftで定義された一意ID)

(楽天レシピのID)

(楽天レシピの調理時間)

(楽天レシピの公開日)

(楽天レシピの画像URL)

(楽天レシピの詳細ページURL)

カラム名一覧:

id:Int

memo:String

created:Date

(このテーブルの一意ID)

(レシピアーカイブにつけるメモ)

(選択した日付)

One ポイントになる部分(Realmの特性を利用)

どのようなデータを持つかを決定する際に、 プライマリキー(一意になるID)を持つことができる ので、データの関連付けがしやすいと感じた。

※イメージ図

Archive (id=1)

Recipe (id=1)

(archive_id=1)

Recipe (id=n)

(archive_id=1)・・・

【ポイント】

Archive.id =

Recipe.archive_id

Page 10: 指の動きや遷移時等のアニメーションを生かしたUIのサンプル解説

✦ UICollectionViewのセルにUILongPressGestureRecognizerを付与

レシピ画像をドラッグ&ドロップで選択

イベント発生までのタップ時間の設定や指のズレの許容範囲を設定できるのでより細かい設定が可能です。

★画像のドラッグ&ドロップに関する処理を行う直前のトリガーとして活用

//セルに表示する値を設定する internal func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { //セルの定義を行う let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "RecipeCell", for: indexPath) as! RecipeCell

//(省略)セルへ受け渡された値を設定する

//cellのタグを決定する(LongPressGestureRecognizerからの逆引き用に設定) cell.tag = indexPath.row //LongPressGestureRecognizerの定義を行う let longPressGesture = UILongPressGestureRecognizer(target: self, action: #selector(MakeRecipeController.longPressCell(sender:))) //イベント発生までのタップ時間:0.24秒 longPressGesture.minimumPressDuration = 0.24 //指のズレを許容する範囲:10px longPressGesture.allowableMovement = 10.0 //セルに対してLongTapGestureRecognizerを付与する cell.addGestureRecognizer(longPressGesture) return cell }

longPressCellメソッド内で選択したセルの識別とドラッグ&ドロップの実処理部分を行う。

※TapGestureやPanGestureではダメなのか?

上記でも可能ではあるが、TapやPanではタイミングが早すぎるor動きとして不自然な感じがしたためにこの実装にしました。

Page 11: 指の動きや遷移時等のアニメーションを生かしたUIのサンプル解説

✦ iOS7から遷移時のアニメーションを独自に定義することが可能

UIScrollView内に表示されているレシピ画像のサムネイルが画面全体に広がって表示されていくイメージ。

★本サンプルにおける設計は下記のような形を想定して実装する

CustomTransitionの設計

GalleryController.swift

カスタムトランジションの遷移イメージ

(選択レシピ一覧)

Tap1

UIScrollView

Tap2

presented : サムネイル画像が画面全体拡大

GalleryDetailController.swift

(選択レシピ詳細)

画面遷移時 CustomTransition.swift

詳細情報表示

Tap1

Tap2

どの方向の遷移かは、 var presenting: Bool

の状態で決定する

dismissed : サムネイル画像が元の位置に戻る

Page 12: 指の動きや遷移時等のアニメーションを生かしたUIのサンプル解説

✦ NSObjectを継承&UIViewControllerAnimatedTransitioningを適用

アニメーションを行う実体となるContainerViewの中に遷移元・遷移先の情報とロジックを記載する形に。

★設定するのは動きの秒数と画面遷移時のアニメーション実体となるContainerView

CustomTransitionの実装(Classファイル)

//アニメーションの時間を定義する internal func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { return (アニメーションの動作時間) } //アニメーションの実装を定義する internal func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {

�//(流れ1) コンテキストを元にViewないしはViewControllerのインスタンスを取得する(存在しない場合は処理を終了)

�//(流れ2) アニメーションの実態となるコンテナビューを作成

�//(流れ3) 拡大・縮小等の処理を記載しアニメーションの実体となるContainerViewに必要なものを追加する ����UIView.animate(withDuration: (アニメーションの動作時間), delay: 0.0, options: .curveEaseOut, animations: { �����//アニメーション処理の中身 �}, completion:{ finished in ����transitionContext.completeTransition(true) �}) } transitionContext = 遷移元や遷移先のViewControllerやそのほか関連する情報が格納されているもの

Page 13: 指の動きや遷移時等のアニメーションを生かしたUIのサンプル解説

✦ 遷移時のアクションのpresented側にtransitionDelegateを適用

遷移用クラスのインスタンスをViewController側で作りUIViewControllerTransitioningDelegateを適用する

★適用させるプロトコル:UIViewControllerTransitioningDelegate

CustomTransitionの基本例(Modal遷移)

//進む場合のアニメーションの設定を行う internal func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? { return (UIViewControllerAnimatedTansitioningのインスタンス) } //戻る場合のアニメーションの設定を行う internal func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { return (UIViewControllerAnimatedTansitioningのインスタンス) }

このケースはModalでの遷移をCustomTransitionを活用してカスタマイズすることを想定しています。

遷移用のClass内でPresented/Dismissの場合分けが行えるような形で実装をしておく。

ポイント:

※UINavigationControllerと併用してPush/Popの遷移アニメーションのカスタマイズも可能

該当のViewControllerで遷移用Classのインスタンスを作成しPresented/Dismissの設定を行う。

Page 14: 指の動きや遷移時等のアニメーションを生かしたUIのサンプル解説

✦ 基本はContainerViewを2枚使用したアニメーションを伴う実装

ContainerViewの設計及び実装の仕方によってはメニュー開閉用ライブラリのような動きを実装できます。

★メニュー部分の開閉用プロトコルを定義しておき処理実体は大元の部分で行う

コンテンツ下に隠れているメニューの実装

コンテンツ表示用とサブメニュー用のContainerViewの関係図

メニュー部分開閉処理に関して

Navigation Controller

MenuController.swift…

各メインコンテンツ (はじまりになる所)

MakeRecipeController.swift

Storyboard上での重なり順

UINavigationController (コンテンツ部分)…

ViewController.swift…

ViewController.swift … 各種プロトコルの実体処理を記載する

MenuController.swift … メニューを閉じるプロトコル(MenuCloseDelegate)を定義

MakeRecipeController.swift … メニューを開くプロトコル(MenuOpenDelegate)を定義

Page 15: 指の動きや遷移時等のアニメーションを生かしたUIのサンプル解説

✦ 指の動きや遷移・アニメーションでUIに動きを加えた実装は面白い

今回のまとめ

ご清聴ありがとうございました!またこのような機会があった際には是非ともよろしくお願い致します!

★ユーザーの指の動きを想定したUIを組み立てる際の表現はとても面白い

選択時のドラッグ&ドロップの手前での要素検知やメニュー開閉のトリガーにも応用可能

★アニメーションを伴う実装もうまく組み合わせてさらにカッコいい表現も

ModalやNavigationControllerでの画面遷移にも工夫を加えることでより表現がリッチにできる

★デバッグや実装は慎重に行わないと思わぬところで落とし穴がある

UI部分の実装はテストコードだけでもバグや予期せぬ動作を検知しにくい部分なので注意

★自分ルール

【良いアウトプットのために】

発表・登壇時はこの中のいずれか2つを

絶対に準備するルールを設けています!