Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Introduction to micro interactions for iOS apps

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などのアプリで積極的に採用されており、自分のアプリにも入れてみたい、という方に向けて、マイクロインタラクションの使いどころや実装例を紹介します。

kiwi

September 02, 2018
Tweet

More Decks by kiwi

Other Decks in Technology

Transcript

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

    View full-size slide

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

    View full-size slide

  3. ࣗݾ঺հ
    kiwi (キウイ)
    koga_wiwi
    kiwi-26

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  17. Ϧονͳදݱ͕Ͱ͖Δ
    ૂ͑ΔޮՌ
    • ϫΫϫΫײ
    • ੈք؍ͷදݱ
    ࢖͍Ͳ͜Ζ
    • ήʔϜͳͲੈք؍͕ڧ͍ΞϓϦ
    • ΢ΥʔΫεϧʔը໘
    5PLZP %JTOFZ3FTPSU"QQ
    ΢ΥʔΫεϧʔը໘
    ىಈ࣌ͷζʔϜͷಈ͖

    View full-size slide

  18. ଟ͘ͷ৘ใΛ఻͑Δ͜ͱ͕Ͱ͖Δ
    ૂ͑ΔޮՌ
    • ཧղ͠΍͢͞ͷ޲্
    ࢖͍Ͳ͜Ζ
    • λοϓ࣌ͷΦϒδΣΫτͷมԽ
    ૢ࡞ͷ੒ޭΛϑΟʔυόοΫ

    • ը໘ભҠ
    • άϥϑͷ࣌ܥྻදࣔ
    /JLF3VO$MVC
    ϥϯͷৄࡉը໘Ͱͷ
    ૸ߦϧʔτදࣔͷಈ͖

    View full-size slide

  19. ஫ҙΛҾ͘
    ૂ͑ΔޮՌ
    • ը໘ͷҰ෦Λಈ͔ͯ͠஫໨ͤ͞Δ
    ࢖͍Ͳ͜Ζ
    • Χʔτ௥ՃͷΞχϝʔγϣϯ
    • ͦͷ΄͔ը໘ͷҰ෦ʹ஫໨͍ͤͨ͞ͱ͖
    NJOOF
    ঎඼ΛΧʔτʹ
    ೖΕͨͱ͖ͷಈ͖

    View full-size slide

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

    View full-size slide

  21. ࡞ͬͯΈΑ͏

    View full-size slide

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

    View full-size slide

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

    *OTUBHSBN
    ͍͍ͶϘλϯͷಈ͖

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  27. ΞχϝʔγϣϯΛ࡞ͬͯΈΔr ΆΑΜͱ͢ΔϘλϯ
    • ඵ਺ͱΞχϝʔγϣϯऴྃޙͷঢ়ଶʢΫϩʔδϟʣΛࢦఆ͢Δͱɺ
    ͦͷؒΛࣗಈͰิؒͯ͠Ξχϝʔγϣϯͯ͘͠ΕΔ
    • ࢦఆͰ͖Δ಺༰͸6*7JFXͷϓϩύςΟ
    • GSBNF΍CPVOETɺഎܠ৭ɺಁ໌౓
    • USBOTGPSN ճస ֦େॖখ
    %BZ-5!5SBDL#
    • ஗Εඵ਺΍ΠʔζΠϯΞ΢τɺऴྃޙͷॲཧͷࢦఆ͕Մೳͳ೿ੜܕ΋
    • ऴྃॲཧͰผͷΞχϝʔγϣϯΛೖΕΔ͜ͱͰɺ࿈ଓͨ͠Ξχϝʔ
    γϣϯ͕Մೳ
    UIView.animate(withDuration:animations:)

    View full-size slide

  28. ΞχϝʔγϣϯΛ࡞ͬͯΈΔ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)

    View full-size slide

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

    View full-size slide

  30. ΞχϝʔγϣϯΛ࡞ͬͯΈΔ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)

    View full-size slide

  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)

    View full-size slide

  32. σϞ
    ʢ͜͜ʹσϞΛೖΕΔʣ

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  36. ΞχϝʔγϣϯΛ࡞ͬͯΈΔ ը໘ભҠ
    • ը໘ؒͰͲΜͳભҠΛ͢Δ͔Λදͨ͢Ίͷϓϩτίϧ
    • 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
    ...

    View full-size slide

  37. ΞχϝʔγϣϯΛ࡞ͬͯΈΔ ը໘ભҠ
    • USBOTJUJPO$POUFYUDPOUBJOFS7JFX͕Ξχϝʔγϣϯͷؒදࣔ͞ΕΔ
    • ભҠޙͷ7JFX΍Ξχϝʔγϣϯதʹදࣔ͢Δ7JFXΛDPOUBJOFS7JFXʹ
    BEE4VCWJFX͠ɺΞχϝʔγϣϯͤ͞Δ
    • ࠓճ͸ɺભҠઐ༻ͷ*NBHF7JFXΛDPOUBJOFSʹ௥Ճ͠ɺ
    ϦετͷҐஔ͔Βৄࡉը໘ͰͷҐஔ·Ͱಈ͔͢ͱ͍͏ํ਑
    • ৄࡉΛεέϧτϯදࣔ͠ɺͦͷதͰॳظҐஔ͔Βಈ͔͢ํ๏΋͋Δ
    • Ξχϝʔγϣϯ͕ऴΘͬͨΒ DPOUFYUDPNQMFUF5SBOTJUJPO USVF

    UIViewControllerAnimatedTransitioning プロトコル
    animateTransition(using:) メソッド

    View full-size slide

  38. ࣮૷ྫ
    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)

    View full-size slide

  39. ࣮૷ྫ
    // 詳細画面の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)

    View full-size slide

  40. ࣮૷ྫ
    // 最初の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
    // 非表示にした詳細画面を表示

    View full-size slide

  41. ࣮૷ྫ
    if !self.presenting {
    toView.alpha = 1
    }
    }, completion: { _ in
    // 非表示にした詳細画面を表示
    // 遷移中に表示していたimageViewを削除
    if self.presenting {
    detailView.alpha = 1
    } else {
    self.dismissCompletion?()
    }
    transitionImageView.removeFromSuperview()
    transitionContext.completeTransition(true)
    })
    }

    View full-size slide

  42. σϞ
    ʢ͜͜ʹσϞΛೖΕΔʣ

    View full-size slide

  43. ͓·͚6*7JFX1SPQFSUZ"OJNBUPS ʹ͍ͭͯ
    $PSF"OJNBUJPO
    $"-BZFSͰͷΞχϝʔγϣϯ

    6*7JFX
    $"-BZFSΛ಺෦ʹ͍࣋ͬͯΔ

    6*7JFX1SPQFSUZ"OJNBUPS
    J04ʙ ͍Ζ͍ΖઃఆͰ͖Δ΍ͭ

    ಺෦ͰݺΜͰΔ ಺෦ͰݺΜͰΔʜʜͱࢥ͏
    • ΞχϝʔγϣϯͷҰ࣌ఀࢭ΍ٯ࠶ੜ
    • ΠʔδϯάͷΧʔϒΛࣗ෼Ͱઃఆ
    • ಈతʹΞχϝʔγϣϯΛ௥Ճ
    %BZ !%

    View full-size slide

  44. ͍͞͝ʹ
    • ϚΠΫϩΠϯλϥΫγϣϯΛద੾ʹऔΓೖΕΔ͜ͱͰɺ
    ΞϓϦͷ࢖͍৺஍͕Α͘ͳΓɺϢʔβʔମݧ͕޲্͢Δ
    • ؤுͬͯεςοϓΞοϓ͍͖ͯ͠·͠ΐ͏ʂ
    ՝୊Λ
    ղܾͰ͖Δ
    εϜʔζʹ
    ՝୊ղܾ
    ࢖͍উख

    ՝୊ղܾ͕
    շײʹͳΔ
    ࢖͍৺஍

    ҆ఆͨ͠ಈ࡞
    ը໘ͷߏ੒ཁૉ΍
    ભҠͷ߹ཧԽ
    ಈ࡞ͷΧΫ͖ͭ
    ϚΠΫϩΠϯλϥΫγϣϯ

    View full-size slide

  45. ࢀߟࢿྉ
    • 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

    View full-size slide