Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

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

604 views

Published on

第21回Swiftビギナーズ勉強会での登壇資料になります。

年末年始に作成した「料理レシピの画像を元に直感的にレシピを選択してアーカイブするアプリサンプル」を作成した際の解説資料になります。

ジェスチャーやカスタムトランジション・アニメーションを活用すること指の動きに合わせた動きや画面の切り替えをカスタマイズすることでUIに一工夫を加えてみました。

この資料では実際のコードと合わせて、このサンプルを実装するにあたっての設計部分に関する部分もピックアップしています。

※より具体的にコードの実装を参照する場合は下記の記事も合わせてご覧頂ければと思います。

★詳細解説
・ジェスチャーやカスタムトランジションを利用して入力時やコンテンツ表示時に一工夫を加えたUIの実装ポイントまとめ
http://qiita.com/fumiyasac@github/items/6c4c2b909a821932be04

Published in: Technology
  • Be the first to comment

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

  1. 1. 指の動きや遷移時等のアニメーションを 生かしたUIのサンプル解説 Swiftビギナーズ勉強会 #21 2017/02/18 Fumiya Sakai
  2. 2. 自己紹介と簡単な経歴など ✦ 今までの仕事履歴(本業) 石川県金沢市生まれ 本業はサーバーサイドのプログラマ ※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なんかも
  3. 3. これまでに作ったもの(ネイティブアプリ) ① 簡易家計簿アプリ「Coffre」 ② ゲームアプリ「10秒虫食い算」 ・カレンダーを自作しています ・シンプルなお小遣い帳感覚で支出管理できます ・全問正解者ほとんどいません… ・不定期ですがコラムも書いています ・サーバーサイドはRuby on Railsを使用 http://www.coffre.me/ ・デザインにもこだわってみました(特にグラフ) ・実はちょっとバグがあります。 ・問題は今後追加予定(現在110問収録) 個人的にはなりますが、他にもアプリ・Webサービスなど開発中です(2016年も宜しくお願いします) ・サイト等は次回のアップデートで公開予定 http://blog.just1factory.net/services/284 ・若干の中毒性を含みます
  4. 4. カレンダーが好きでライブラリを作りました 日本の祝祭日を計算で出してくれる ・カレンダーアプリ等での活用を想定 ・シルバーウィーク・ゴールデンウィークも対応 ・ハッピーマンデー法の施行も対応 ・春分の日・秋分の日にも対応 ・過去の祝祭日もおおむね考慮はしている 構想や基本実装は僕ですが、他に4名のContributorのお力添えがあり実運用できるレベルになりました! 職人の手作業で計算しております! ・HTTP(HTTPS)通信は不要 ★CalculateCalendarLogic ver0.1.3 【最新情報】最近はmacOSのサポートがされました! ※CocoaPods / Carthage経由で導入できます。 ・Github: https://github.com/fumiyasac/handMadeCalendarAdvance ・実装解説: http://qiita.com/fumiyasac@github/items/33bfc07ad36dfffcdf8f 【2017年】Swift3系への正式対応をしていますので是非README等を参考に導入してみてください!
  5. 5. ✦ 今回はできるだけ1つのアプリに近しい形になるようにしました 今回紹介するUIサンプルの概略図 食べたいもしくは作ってみたいレシピをアーカイブするアプリのUIに指の動きや遷移を工夫してみました。
  6. 6. ✦ 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 日本の祝祭日の判定
  7. 7. ✦ 画面や機能の役割に応じて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
  8. 8. ✦ 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」ボタンがトリガー
  9. 9. ✦ 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
  10. 10. ✦ 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 動きとして不自然な感じがしたためにこの実 装にしました。
  11. 11. ✦ iOS7から遷移時のアニメーションを独自に定義することが可能 UIScrollView内に表示されているレシピ画像のサムネイルが画面全体に広がって表示されていくイメージ。 ★本サンプルにおける設計は下記のような形を想定して実装する CustomTransitionの設計 GalleryController.swift カスタムトランジションの遷移イメージ (選択レシピ一覧) Tap1 UIScrollView Tap2 presented : サムネイル画像が画面全体拡大 GalleryDetailController.swift (選択レシピ詳細) 画面遷移時 CustomTransition.swift 詳細情報表示 Tap1 Tap2 どの方向の遷移かは、 var presenting: Bool の状態で決定する dismissed : サムネイル画像が元の位置に戻る
  12. 12. ✦ 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やそのほか関連する情報が格納されているもの
  13. 13. ✦ 遷移時のアクションの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の設定を行う。
  14. 14. ✦ 基本はContainerViewを2枚使用したアニメーションを伴う実装 ContainerViewの設計及び実装の仕方によってはメニュー開閉用ライブラリのような動きを実装できます。 ★メニュー部分の開閉用プロトコルを定義しておき処理実体は大元の部分で行う コンテンツ下に隠れているメニューの実装 コンテンツ表示用とサブメニュー用のContainerViewの関係図 メニュー部分開閉処理に関して Navigation Controller MenuController.swift… 各メインコンテンツ (はじまりになる所) MakeRecipeController.swift Storyboard上での重なり順 UINavigationController (コンテンツ部分)… ViewController.swift… 上 下 ViewController.swift … 各種プロトコルの実体処理を記載する MenuController.swift … メニューを閉じるプロトコル(MenuCloseDelegate)を定義 MakeRecipeController.swift … メニューを開くプロトコル(MenuOpenDelegate)を定義
  15. 15. ✦ 指の動きや遷移・アニメーションでUIに動きを加えた実装は面白い 今回のまとめ ご清聴ありがとうございました!またこのような機会があった際には是非ともよろしくお願い致します! ★ユーザーの指の動きを想定したUIを組み立てる際の表現はとても面白い 選択時のドラッグ&ドロップの手前での要素検知やメニュー開閉のトリガーにも応用可能 ★アニメーションを伴う実装もうまく組み合わせてさらにカッコいい表現も ModalやNavigationControllerでの画面遷移にも工夫を加えることでより表現がリッチにできる ★デバッグや実装は慎重に行わないと思わぬところで落とし穴がある UI部分の実装はテストコードだけでもバグや予期せぬ動作を検知しにくい部分なので注意 ★自分ルール 【良いアウトプットのために】 発表・登壇時はこの中のいずれか2つを 絶対に準備するルールを設けています!

×