Introduction to micro interactions for iOS apps

Cfd6a7b025c390205d1dd8765230bca1?s=47 kiwi
September 02, 2018

Introduction to micro interactions for iOS apps

iOSDC 2018 (day3)
「iOSマイクロインタラクション入門」登壇資料
https://fortee.jp/iosdc-japan-2018/proposal/f21bf617-3e9c-4ec0-833c-bc8dbb6965e5

(プロポーザルより)
マイクロインタラクションとは、ユーザーが操作した際に表示される、ちょっとしたアニメーションやフィードバックなどのアクションのことです。
Facebookなどのアプリで積極的に採用されており、自分のアプリにも入れてみたい、という方に向けて、マイクロインタラクションの使いどころや実装例を紹介します。

Cfd6a7b025c390205d1dd8765230bca1?s=128

kiwi

September 02, 2018
Tweet

Transcript

  1. J04ϚΠΫϩΠϯλϥΫγϣϯ ೖ໳ LJXJ!LPHB@XJXJ LJXJ <TBNQMFBQQDPNJOHTPPO> /*'5:-JGFTUZMF$P MUE J04%$ ެ։൛

  2. ެ։൛ʹؔ͢Δ͝஫ҙ • εϥΠυதʹҾ༻ͨ͠ଞࣾΞϓϦͷྫʹ͍ͭͯ͸ɺ ͝໎࿭͕͔͔Δ͜ͱΛආ͚ΔͨΊɺμϛʔը૾ʹஔ͖׵͓͑ͯΓ·͢ɻ • ετΞͷ%-ϦϯΫΛ23ίʔυʹͨ͠΋ͷΛܝࡌ͠·ͨ͠ͷͰɺ ͥͻࣗ͝਎ͷ୺຤Ͱ͝ཡ͍ͩ͘͞ɻ • ঺հͨ͠ΞϓϦͷಈ͖͸ɺ ࣌఺Ͱͷ΋ͷͰ͢ɻ

    ࠓޙΞϓϦͷಈ࡞͸มΘΔ͜ͱ͕͋Γ·͢ͷͰྃ͝ঝ͍ͩ͘͞ɻ
  3. ࣗݾ঺հ kiwi (キウイ) koga_wiwi kiwi-26

  4. None
  5. χϑςΟෆಈ࢈ΞϓϦͱϚΠΫϩΠϯλϥΫγϣϯ ϚΠΫϩ ΠϯλϥΫγϣϯ

  6. J04ϚΠΫϩΠϯλϥΫγϣϯ ೖ໳ LJXJ!LPHB@XJXJ LJXJ <TBNQMFBQQDPNJOHTPPO> /*'5:-JGFTUZMF$P MUE J04%$

  7. ϚΠΫϩΠϯλϥΫγϣϯ

  8. ϚΠΫϩΠϯλϥΫγϣϯ ૬ޓ࡞༻

  9. ϚΠΫϩΠϯλϥΫγϣϯ ૬ޓ࡞༻ ਓ͕ؒԿ͔ΞΫγϣϯΛͨ࣌͠ɺ ૬खଆͷγεςϜ͕ͦͷΞΫγϣϯʹ ରԠͨ͠ϦΞΫγϣϯΛ͢Δ͜ͱ IUUQTGFSSFUQMVTDPN ΑΓҰ෦վม

  10. ϚΠΫϩΠϯλϥΫγϣϯ Ϣʔβʔ͕ΞΫγϣϯͨ͠ࡍʹड͚औΔ γεςϜଆ͔Βͷͪΐͬͱͨ͠ϦΞΫγϣϯ

  11. ඪ४ͷϚΠΫϩΠϯλϥΫγϣϯ ηϧΛλοϓ͢Δͱ ͙͢ʹഎܠ৭͕มΘΔ ࣍ͷ֊૚ͷը໘͕ ӈଆ͔ΒεϥΠυ͢Δ λΠτϧ͕ঃʑʹখ͘͞ͳΓ ͦͷ··໭ΔϘλϯʹͳΔ ઃఆΞϓϦͷτοϓͰ 6*5BCMF7JFXͷ߲໨ηϧΛ λοϓͨ͠ͱ͖ͷಈ͖

  12. ϚΠΫϩΠϯλϥΫγϣϯͷ໾ׂ ૢ࡞ͷ৺஍Α͞ɾշײ

  13. ࢖͍উख ͕Α͘ͳΔ ࢖͍৺஍ ͕Α͘ͳΔ

  14. ͞·͟·ͳϚΠΫϩΠϯλϥΫγϣϯ ର৅ͷ7JFXͷݟͨ໨ʢ৭ͳͲʣͷมԽ ૢ࡞ͨ͠ͱ͖ͷޮՌԻʢྫ5XJUUFSެࣜʣ ૢ࡞Λͨ͠ͱ͖ͷ୺຤ͷৼಈ %BZ !% Ξχϝʔγϣϯ

  15. ΞχϝʔγϣϯΛ࢖ͬͨϚΠΫϩΠϯλϥΫγϣϯ NJOOF

  16. 6TFBOJNBUJPOBOENPUJPOFGGFDUTKVEJDJPVTMZ Ξχϝʔγϣϯ͸ݡ͘࢖͏ɻ %PO`UVTFBOJNBUJPOGPSUIFTBLFPGVTJOHBOJNBUJPO lΞχϝʔγϣϯΛ࢖͏ͨΊzʹΞχϝʔγϣϯΛ࢖Θͳ͍ɻ ӳจ)VNBO*OUFSGBDF(VJEFMJOF "OJNBUJPO ΑΓ

  17. ΞχϝʔγϣϯΛ6*Ͱ࢖͏ͱͰ͖Δ͜ͱ Ϧονͳදݱ͕ Ͱ͖Δ ଟ͘ͷ৘ใΛ ఻͑Δ͜ͱ͕Ͱ͖Δ ஫ҙΛҾ͘ ʮΠϯλʔϑΣΠεͱΞχϝʔγϣϯʯ IUUQTXXXZPVUVCFDPNXBUDI WO0U$*H@P ΑΓ

  18. Ϧονͳදݱ͕Ͱ͖Δ ૂ͑ΔޮՌ • ϫΫϫΫײ • ੈք؍ͷදݱ ࢖͍Ͳ͜Ζ • ήʔϜͳͲੈք؍͕ڧ͍ΞϓϦ •

    ΢ΥʔΫεϧʔը໘ 5PLZP %JTOFZ3FTPSU"QQ ΢ΥʔΫεϧʔը໘ ىಈ࣌ͷζʔϜͷಈ͖
  19. ଟ͘ͷ৘ใΛ఻͑Δ͜ͱ͕Ͱ͖Δ ૂ͑ΔޮՌ • ཧղ͠΍͢͞ͷ޲্ ࢖͍Ͳ͜Ζ • λοϓ࣌ͷΦϒδΣΫτͷมԽ ૢ࡞ͷ੒ޭΛϑΟʔυόοΫ • ը໘ભҠ

    • άϥϑͷ࣌ܥྻදࣔ /JLF 3VO$MVC ϥϯͷৄࡉը໘Ͱͷ ૸ߦϧʔτදࣔͷಈ͖
  20. ஫ҙΛҾ͘ ૂ͑ΔޮՌ • ը໘ͷҰ෦Λಈ͔ͯ͠஫໨ͤ͞Δ ࢖͍Ͳ͜Ζ • Χʔτ௥ՃͷΞχϝʔγϣϯ • ͦͷ΄͔ը໘ͷҰ෦ʹ஫໨͍ͤͨ͞ͱ͖ NJOOF

    ঎඼ΛΧʔτʹ ೖΕͨͱ͖ͷಈ͖
  21. ΞχϝʔγϣϯΛ6*Ͱ࢖͏ͱͰ͖Δ͜ͱ Ϧονͳදݱ͕ Ͱ͖Δ ଟ͘ͷ৘ใΛ ఻͑Δ͜ͱ͕Ͱ͖Δ ஫ҙΛҾ͘ ʮΠϯλʔϑΣΠεͱΞχϝʔγϣϯʯ IUUQTXXXZPVUVCFDPNXBUDI WO0U$*H@P ΑΓ

  22. ࡞ͬͯΈΑ͏

  23. ͓୊ ԡ͢ͱbΆΑΜ`ͱ͢ΔϘλϯ

  24. ΞχϝʔγϣϯΛ࡞ͬͯΈΔr ΆΑΜͱ͢ΔϘλϯ Ϙλϯλοϓʹର͢ΔϑΟʔυόοΫͷछ *OTUBHSBN ΄͔ଟ͘ͷΞϓϦͰಋೖ ͳʹ΋ͳ͍ͱ͜Ζ͔Β·ͣೖΕͯΈ͍ͨ ͕͋͜ΕΔΞχϝʔγϣϯ/P ཁग़య *OTUBHSBN ͍͍ͶϘλϯͷಈ͖

  25. ΞχϝʔγϣϯΛ࡞ͬͯΈΔr ΆΑΜͱ͢ΔϘλϯ ͲΜͳಈ͖Λ͍ͯ͠Δͷ͔ ίϚૹΓͯ͠ΈΔ ࣸਅΞϓϦΛ࢖͍ɺ ಈըͷαϜωΠϧΛΏͬ͘ΓεϥΠυͯ͠ Ξχϝʔγϣϯͷಈ͖Λ֬ೝ͍ͯ͠Δ༷ࢠ

  26. ΞχϝʔγϣϯΛ࡞ͬͯΈΔr ΆΑΜͱ͢ΔϘλϯ Α͘ݟΔͱɺখ͘͞ͳ͔ͬͯΒɺେ͖͘ͳͬͯΔ *OTUBHSBN

  27. ΞχϝʔγϣϯΛ࡞ͬͯΈΔr ΆΑΜͱ͢ΔϘλϯ ΆΑΜͱ͢Δʢόωͷಈ͖ͷʣΞχϝʔγϣϯͷઐ໳Ո UIView.animate(withDuration:delay:usingSpringWithDamping:initial SpringVelocity:options:animations:completion:)

  28. ΞχϝʔγϣϯΛ࡞ͬͯΈΔr ΆΑΜͱ͢ΔϘλϯ • ඵ਺ͱΞχϝʔγϣϯऴྃޙͷঢ়ଶʢΫϩʔδϟʣΛࢦఆ͢Δͱɺ ͦͷؒΛࣗಈͰิؒͯ͠Ξχϝʔγϣϯͯ͘͠ΕΔ • ࢦఆͰ͖Δ಺༰͸6*7JFXͷϓϩύςΟ • GSBNF΍CPVOETɺഎܠ৭ɺಁ໌౓ •

    USBOTGPSN ճస ֦େॖখ  %BZ-5!5SBDL# • ஗Εඵ਺΍ΠʔζΠϯΞ΢τɺऴྃޙͷॲཧͷࢦఆ͕Մೳͳ೿ੜܕ΋ • ऴྃॲཧͰผͷΞχϝʔγϣϯΛೖΕΔ͜ͱͰɺ࿈ଓͨ͠Ξχϝʔ γϣϯ͕Մೳ UIView.animate(withDuration:animations:)
  29. ΞχϝʔγϣϯΛ࡞ͬͯΈΔr ΆΑΜͱ͢ΔϘλϯ UIView.animate(withDuration:animations:) imageView.bounds.size = CGSize(width: 36, height: 36) UIView.animate(

    withDuration: 0.3, // 秒数 delay: 0, // 0秒後に開始 options: .curveEaseIn, // オプション(カーブ, リピート等) animations: { self.imageView.bounds.size = CGSize(width: 44, height: 44) }, completion: nil)
  30. ΞχϝʔγϣϯΛ࡞ͬͯΈΔr ΆΑΜͱ͢ΔϘλϯ ΆΑΜͱ͢Δʢόωͷಈ͖ͷʣΞχϝʔγϣϯͷઐ໳Ո UIView.animate(withDuration:delay:usingSpringWithDamping:initial SpringVelocity:options:animations:completion:)

  31. ΞχϝʔγϣϯΛ࡞ͬͯΈΔr ΆΑΜͱ͢ΔϘλϯ imageView.bounds.size = CGSize(width: 36*0.7, height: 36*0.7) UIView.animate( withDuration:

    0.4, delay: 0.0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.0, options: .curveEaseInOut, animations: { self.imageView.bounds.size = CGSize(width: 36, height: 36) }, completion: nil)
  32. ΞχϝʔγϣϯΛ࡞ͬͯΈΔr ΆΑΜͱ͢ΔϘλϯ imageView.bounds.size = CGSize(width: 36*0.7, height: 36*0.7) UIView.animate( withDuration:

    0.4, delay: 0.0, usingSpringWithDamping: 0.5, // バネの振幅 initialSpringVelocity: 0.0, // バネの初速 options: .curveEaseInOut, animations: { self.imageView.bounds.size = CGSize(width: 36, height: 36) }, completion: nil)
  33. σϞ ʢ͜͜ʹσϞΛೖΕΔʣ

  34. ͓୊ ը૾͕Ҡಈ͠ͳ͕Βը໘ભҠ

  35. ΞχϝʔγϣϯΛ࡞ͬͯΈΔ ը໘ભҠ ࣍ͷը໘ͱڞ௨ͷཁૉΛɺ࣍ͷը໘ʹ߹Θͤͯ Ґஔͷมߋɾ֦େॖখΛߦ͍ͳ͕Βܧଓදࣔ ը໘ؒͷؔ܎ΛΑΓڧ͘ఏࣔ͢Δ

  36. ΞχϝʔγϣϯΛ࡞ͬͯΈΔ ը໘ભҠ ࣍ͷը໘ͱڞ௨ͷཁૉΛɺ࣍ͷը໘ʹ߹Θͤͯ Ґஔͷมߋɾ֦େॖখΛߦ͍ͳ͕Βܧଓදࣔ ը໘ؒͷؔ܎ΛΑΓڧ͘ఏࣔ͢Δ 1JOUFSFTU΍NJOOFͳͲͰ࢖༻ ϚςϦΞϧσβΠϯͰ΋༗໊ NJOOF ঎඼ͷҰཡ͔Β ৄࡉʹભҠ͢Δಈ͖

  37. ΞχϝʔγϣϯΛ࡞ͬͯΈΔ ը໘ભҠ • ը໘ؒͰͲΜͳભҠΛ͢Δ͔Λදͨ͢Ίͷϓϩτίϧ • VTJOHͰ౉͞ΕΔ 6*7JFX$POUSPMMFS$POUFYU5SBOTJUJPOJOHܕͷҾ਺ ͔Βɺલޙͷ7JFX$POUSPMMFS΍7JFX͕औಘՄೳ UIViewControllerAnimatedTransitioning プロトコル

    animateTransition(using:) メソッド func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { let containerView = transitionContext.containerView // アニメーション中のcontainer let fromView = transitionContext.view(forKey: .from)! // 今まで表示していたview let toView = transitionContext.view(forKey: .to)! // これから表示するview ...
  38. ΞχϝʔγϣϯΛ࡞ͬͯΈΔ ը໘ભҠ • USBOTJUJPO$POUFYUDPOUBJOFS7JFX͕Ξχϝʔγϣϯͷؒදࣔ͞ΕΔ • ભҠޙͷ7JFX΍Ξχϝʔγϣϯதʹදࣔ͢Δ7JFXΛDPOUBJOFS7JFXʹ BEE4VCWJFX͠ɺΞχϝʔγϣϯͤ͞Δ • ࠓճ͸ɺભҠઐ༻ͷ*NBHF7JFXΛDPOUBJOFSʹ௥Ճ͠ɺ ϦετͷҐஔ͔Βৄࡉը໘ͰͷҐஔ·Ͱಈ͔͢ͱ͍͏ํ਑

    • ৄࡉΛεέϧτϯදࣔ͠ɺͦͷதͰॳظҐஔ͔Βಈ͔͢ํ๏΋͋Δ • Ξχϝʔγϣϯ͕ऴΘͬͨΒ DPOUFYUDPNQMFUF5SBOTJUJPO USVF UIViewControllerAnimatedTransitioning プロトコル animateTransition(using:) メソッド
  39. ࣮૷ྫ   func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { presenting =

    operation == UINavigationControllerOperation.push // containerView, fromView, toView を取得 let containerView = transitionContext.containerView let fromView = transitionContext.view(forKey: .from)! let toView = transitionContext.view(forKey: .to)! // 詳細画面側のViewを取得し、アニメーション中は非表示にする let detailView = presenting ? toView : fromView toView.alpha = 0 // 詳細画面のImageViewの位置, 遷移用ImageViewの初期位置と最終位置 let detailFrame = CGRect(x: 0, y: 64, width: detailView.frame.width, height: detailView.frame.width)
  40. ࣮૷ྫ   // 詳細画面のImageViewの位置, 遷移用ImageViewの初期位置と最終位置 let detailFrame = CGRect(x:

    0, y: 64, width: detailView.frame.width, height: detailView.frame.width) let initialFrame = presenting ? originFrame : detailFrame let finalFrame = presenting ? detailFrame : originFrame // 遷移中のみ表示させるImageView let transitionImageView = UIImageView(frame: initialFrame) transitionImageView.image = listImageView.image transitionImageView.contentMode = .scaleAspectFill transitionImageView.clipsToBounds = true containerView.addSubview(toView) containerView.addSubview(transitionImageView) containerView.bringSubview(toFront: transitionImageView)
  41. ࣮૷ྫ   // 最初の0.2秒で遷移元の画面を非表示にする // containerViewに追加しているImageViewだけが表示される UIView.animate(withDuration: duration/5, animations:

    { fromView.alpha = 0 }) // 0.2秒後からEaseInOutでImageViewの位置を移動 // 合わせて、一覧に戻る遷移の場合は一覧画面を徐々に表示 UIView.animate(withDuration: duration*4/5, delay: duration/5, options: [.curveEaseInOut], animations: { transitionImageView.frame = finalFrame if !self.presenting { toView.alpha = 1 } }, completion: { _ in // 非表示にした詳細画面を表示
  42. ࣮૷ྫ   if !self.presenting { toView.alpha = 1 }

    }, completion: { _ in // 非表示にした詳細画面を表示 // 遷移中に表示していたimageViewを削除 if self.presenting { detailView.alpha = 1 } else { self.dismissCompletion?() } transitionImageView.removeFromSuperview() transitionContext.completeTransition(true) }) }
  43. σϞ ʢ͜͜ʹσϞΛೖΕΔʣ

  44. ͓·͚6*7JFX1SPQFSUZ"OJNBUPS ʹ͍ͭͯ $PSF"OJNBUJPO $"-BZFSͰͷΞχϝʔγϣϯ 6*7JFX $"-BZFSΛ಺෦ʹ͍࣋ͬͯΔ 6*7JFX1SPQFSUZ"OJNBUPS J04ʙ ͍Ζ͍ΖઃఆͰ͖Δ΍ͭ ಺෦ͰݺΜͰΔ

    ಺෦ͰݺΜͰΔʜʜͱࢥ͏ • ΞχϝʔγϣϯͷҰ࣌ఀࢭ΍ٯ࠶ੜ • ΠʔδϯάͷΧʔϒΛࣗ෼Ͱઃఆ • ಈతʹΞχϝʔγϣϯΛ௥Ճ %BZ !%
  45. ͍͞͝ʹ • ϚΠΫϩΠϯλϥΫγϣϯΛద੾ʹऔΓೖΕΔ͜ͱͰɺ ΞϓϦͷ࢖͍৺஍͕Α͘ͳΓɺϢʔβʔମݧ͕޲্͢Δ • ؤுͬͯεςοϓΞοϓ͍͖ͯ͠·͠ΐ͏ʂ ՝୊Λ ղܾͰ͖Δ εϜʔζʹ ՝୊ղܾ

    ࢖͍উख ՝୊ղܾ͕ շײʹͳΔ ࢖͍৺஍ ҆ఆͨ͠ಈ࡞ ը໘ͷߏ੒ཁૉ΍ ભҠͷ߹ཧԽ ಈ࡞ͷΧΫ͖ͭ ϚΠΫϩΠϯλϥΫγϣϯ
  46. ࢀߟࢿྉ • 6*7JFX "OJNBUJPO$PSF"OJNBUJPO • IUUQTEFWFMPQFSBQQMFDPNKQEPDVNFOUBUJPO7JFX1(@J1IPOF04QEG • IUUQTEFWFMPQFSBQQMFDPNKQEPDVNFOUBUJPO$PSF"OJNBUJPO@HVJEFQEG • IUUQTTUPSFSBZXFOEFSMJDIDPNQSPEVDUTJPTBOJNBUJPOTCZUVUPSJBMT

    • IUUQTRJJUBDPNIBDIJOPCVJUFNTEDDCB • 6*7JFX1SPQFSUZ"OJNBUPS • IUUQTEFWFMPQFSBQQMFDPNEPDVNFOUBUJPOVJLJUBOJNBUJPO@BOE@IBQUJDT QSPQFSUZ@CBTFE@BOJNBUJPOT • IUUQTTQFBLFSEFDLDPNIFEKJSPHJOUSPEVDUJPOUP VJWJFXQSPQFSUZBOJNBUPS • IUUQTTQFBLFSEFDLDPNIFEKJSPHVJWJFXQSPQFSUZBOJNBUPSEFTIJYJBO TVSVSJUVUJOBBOJNFTJZPOCJBPYJBO