Slide 1

Slide 1 text

Swipe Transition #potatotips 47 ాத ୡ໵ (@tattn)

Slide 2

Slide 2 text

• Yahoo!৐׵Ҋ಺ • iOSΞϓϦΤϯδχΞ • GitHub: @tattn • Qiita: @tattn • Twitter: @tanakasan2525 ాத ୡ໵ (@tattn)

Slide 3

Slide 3 text

Α͋͘Δ
 ศརͳεϫΠϓδΣενϟʔ Λ࣮૷ͯ͠Έ·ͨ͠

Slide 4

Slide 4 text

ͲͷҐஔͰ΋ εϫΠϓόοΫͰ͖Δ

Slide 5

Slide 5 text

ը໘ͷͲ͜Ͱ΋ࠨʹεϫΠϓͰ͖Δ ը໘୺(Τοδ)Ͱͳͯ͘΋OK

Slide 6

Slide 6 text

Sloppy Swiping ͱ΋ݺ͹Ε͍ͯ·͢ɻ ͜ͷεϥΠυͰ͸γϯϓϧʹ
 SwipeBackͱදه͠·͢ɻ

Slide 7

Slide 7 text

ԼεϫΠϓͰϞʔμϧΛด͡Δ

Slide 8

Slide 8 text

ԼʹεϫΠϓ͢ΔͱϞʔμϧͷը໘͕εϫΠϓͱͱ΋ʹҠಈ͠ɺ
 ͋Δఔ౓εΫϩʔϧ͢Δͱด͡Δ

Slide 9

Slide 9 text

͜ͷεϥΠυͰ͸
 SwipeToDismissͱදه͠·͢ɻ

Slide 10

Slide 10 text

࣮૷ͯ͠Έ·ͨ͠ͷͰɺ
 ͦͷ࣮૷ํ๏Λ͝঺հ͠·͢

Slide 11

Slide 11 text

࣮૷ํ๏

Slide 12

Slide 12 text

ࠓճͷओͳొ৔ਓ෺ • UIPanGestureRecognizer • UIViewControllerAnimatedTransitioning • UIViewControllerTransitioningDelegate • UINavigationControllerDelegate • UIPercentDrivenInteractiveTransition

Slide 13

Slide 13 text

UIPanGestureRecognizer ࢦͷҠಈྔͳͲΛऔಘͰ͖ΔΫϥεɻ ࠓճ͸͜ΕͰεϫΠϓΛݕग़͠·͢ɻ IUUQTEFWFMPQFSBQQMFDPNEPDVNFOUBUJPOVJLJUVJQBOHFTUVSFSFDPHOJ[FS

Slide 14

Slide 14 text

UIViewControllerAnimatedTransitioning ࣗ࡞ͷը໘ભҠΛ࣮૷Ͱ͖Δϓϩτίϧɻ SwipeBackͰ͸ViewΛӈʹҠಈɺ
 SwipeToDismissͰ͸ViewΛԼʹҠಈ
 ͢ΔͨΊʹ࢖༻͠·͢ɻ IUUQTEFWFMPQFSBQQMFDPNEPDVNFOUBUJPOVJLJUVJWJFXDPOUSPMMFSBOJNBUFEUSBOTJUJPOJOH

Slide 15

Slide 15 text

UIViewControllerTransitioningDelegate present/dismiss࣌ʹ
 Ͳͷτϥϯδγϣϯ(UIViewControllerAnimatedTransitioning)Λ
 ར༻͢Δͷ͔Λࢦఆ͢Δϓϩτίϧɻ 
 SwipeToDismissͰࣗ࡞ͷը໘ભҠΛར༻͢ΔͨΊʹ
 ࢖༻͠·͢ɻ IUUQTEFWFMPQFSBQQMFDPNEPDVNFOUBUJPOVJLJUVJWJFXDPOUSPMMFSUSBOTJUJPOJOHEFMFHBUF

Slide 16

Slide 16 text

UINavigationControllerDelegate UINavigationControllerͰൃੜ͢ΔΠϕϯτͷัଊ΍
 Ͳͷτϥϯδγϣϯ(UIViewControllerAnimatedTransitioning)Λ
 ར༻͢Δͷ͔Λࢦఆ͢Δϓϩτίϧɻ 
 SwipeBackͰࣗ࡞ͷը໘ભҠΛར༻͢ΔͨΊʹ
 ࢖༻͠·͢ɻ IUUQTEFWFMPQFSBQQMFDPNEPDVNFOUBUJPOVJLJUVJOBWJHBUJPODPOUSPMMFSEFMFHBUF

Slide 17

Slide 17 text

UIPercentDrivenInteractiveTransition ը໘ભҠͷิؒํ๏ͷࢦఆ΍
 ը໘ભҠ͕Կ%׬͍ྃͯ͠Δͷ͔ͳͲΛ
 ઃఆ͢ΔΫϥεɻ
 
 SwipeBackͱSwipeToDismissͰ
 Ͳ͜·ͰεϫΠϓͨ͠ͷ͔Λදݱ͢ΔͨΊʹ࢖༻͠·͢ɻ IUUQTEFWFMPQFSBQQMFDPNEPDVNFOUBUJPOVJLJUVJQFSDFOUESJWFOJOUFSBDUJWFUSBOTJUJPO

Slide 18

Slide 18 text

(ൃද࣌ؒͷؔ܎Ͱ)
 SwipeBackͷํΛ঺հ͠·͢ɻ (SwipeToDismiss΋΄΅ಉ࣮͡૷Ͱग़དྷ·͢ɻ)

Slide 19

Slide 19 text

SwipeBackAnimator class SwipeBackAnimator: NSObject, UIViewControllerAnimatedTransitioning { func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { guard let to = transitionContext.viewController(forKey: .to), let from = transitionContext.viewController(forKey: .from) else { return } let containerView = transitionContext.containerView containerView.insertSubview(to.view, belowSubview: from.view) to.view.frame = containerView.frame ભҠݩͷviewͷԼʹભҠޙͷviewΛinsert͍ͯ͠·͢ɻ
 SwipeBack࣌ʹԼͷViewΛදࣔ͢ΔͨΊͰ͢ɻ

Slide 20

Slide 20 text

͜ͷ෦෼

Slide 21

Slide 21 text

SwipeBackAnimator // ύϥϥοΫεޮՌ to.view.transform.tx = -containerView.bounds.width * 0.3 UIView.animate( withDuration: transitionDuration(using: transitionContext), delay: 0, options: .curveLinear, animations: { to.view.transform = .identity from.view.transform = CGAffineTransform(translationX: to.view.frame.width, y: 0) }, completion: { _ in from.view.transform = .identity transitionContext.completeTransition( !transitionContext.transitionWasCancelled ) }) ભҠޙͷviewʹύϥϥοΫεޮՌΛ෇͚ͭͭɺ
 ભҠલͷviewΛӈ΁Ҡಈ

Slide 22

Slide 22 text

SwipeBackNavigationController class SwipeBackNavigationController: UINavigationController { private let animator = SwipeBackAnimator() private var interactiveTransition: UIPercentDrivenInteractiveTransition! override func viewDidLoad() { super.viewDidLoad() delegate = self let panGesture = UIPanGestureRecognizer() panGesture.addTarget(self, action: #selector(handlePanGesture(_:))) panGesture.maximumNumberOfTouches = 1 view.addGestureRecognizer(panGesture) } viewʹUIPanGestureRecognizerͱ
 UINavigationControllerDelegateΛηοτ

Slide 23

Slide 23 text

SwipeBackNavigationController extension SwipeBackNavigationController: UINavigationControllerDelegate { public func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationControllerOperation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? { return operation == .pop ? animator : nil } public func navigationController(_ navigationController: UINavigationController, interactionControllerFor animationController: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? { return interactiveTransition } } ར༻͢Δࣗ࡞ͷτϥϯδγϣϯΛฦ͢ɻ (εϥΠυʹࡌͤΔͱਏ͍ݟͨ໨Ͱ͕͢ɺ࣮૷͍ͯ͠Δͷ͸2ߦͰ͢)

Slide 24

Slide 24 text

SwipeBackNavigationController @objc private func handlePanGesture(_ recognizer: UIPanGestureRecognizer) { switch recognizer.state { case .began: interactiveTransition = UIPercentDrivenInteractiveTransition() interactiveTransition.completionCurve = .linear popViewController(animated: true) case .changed: let translation = recognizer.translation(in: view) interactiveTransition.update(translation.x / view.bounds.width) case .ended: if recognizer.velocity(in: view).x > 0 { interactiveTransition.finish() interactiveTransition = nil } else { fallthrough } case .cancelled: interactiveTransition.cancel() interactiveTransition = nil default: break } } δΣενϟʔʹ߹Θͤͯঢ়ଶΛߋ৽

Slide 25

Slide 25 text

׬੒ 100ߦຬͨͳ͍ίʔυͰ
 γϯϓϧͳSwipeBackΛ࣮૷Ͱ͖·ͨ͠ɻ ࠓճͷ࣮૷͸ˣʹஔ͍ͯ͋Γ·͢ɻ https://github.com/tattn/SwipeTransitionExample

Slide 26

Slide 26 text

ϥΠϒϥϦԽ

Slide 27

Slide 27 text

͔ͤͬ͘ͳͷͰϥΠϒϥϦԽ͠·ͨ͠ https://github.com/tattn/SwipeTransition ScrollView͕͋ͬͯ΋ಈ࡞͢ΔΑ͏ʹͨ͠Γɺ
 Method SwizzlingͰશը໘ʹద༻͢Δػೳ΋͋Γ·͢ɻ SwipeTransition ͥͻɺ͓ࢼ͍ͩ͘͠͞ʂ

Slide 28

Slide 28 text

·ͱΊ

Slide 29

Slide 29 text

·ͱΊ ʘδΣενϟʔͰૉఢUXΛ໨ࢦͦ͏ʗ
 ʘʘ\\٩( 'ω' )و //ʗʗ ఏڙ͞Ε͍ͯΔ࢓૊ΈΛར༻͢Δ͜ͱͰ
 ҙ֎ͱ؆୯ʹ࣮૷͢Δ͜ͱ͕ग़དྷ·ͨ͠