From 75bf9aa9e4fcd1d65e8147044fb8787661e5df08 Mon Sep 17 00:00:00 2001 From: Eric Tang Date: Fri, 16 Jun 2017 23:19:09 -0400 Subject: [PATCH] Add support for interactive transitioning https://github.com/material-motion/transitioning-objc/issues/3 --- src/MDMTransition.h | 7 ++++ src/MDMTransitionContext.h | 10 +++++ src/MDMTransitionController.h | 2 +- src/UIViewController+TransitionController.h | 2 + src/UIViewController+TransitionController.m | 10 +++++ .../MDMPresentationTransitionController.m | 40 +++++++++++++++++++ .../MDMViewControllerTransitionContext.h | 2 +- .../MDMViewControllerTransitionContext.m | 29 +++++++++++++- 8 files changed, 98 insertions(+), 4 deletions(-) diff --git a/src/MDMTransition.h b/src/MDMTransition.h index de8eda7..7ecd469 100644 --- a/src/MDMTransition.h +++ b/src/MDMTransition.h @@ -17,6 +17,7 @@ #import @protocol MDMTransitionContext; +@protocol MDMInteractiveTransitionContext; /** A transition coordinates the animated presentation or dismissal of a view controller. @@ -111,3 +112,9 @@ NS_SWIFT_NAME(presentationController(forPresented:presenting:source:)); // clang-format on @end + +NS_SWIFT_NAME(InteractiveTransition) +@protocol MDMInteractiveTransition +- (Boolean)isInteractive:(nonnull id)context; +- (void)startWithInteractiveContext:(nonnull id)context; +@end diff --git a/src/MDMTransitionContext.h b/src/MDMTransitionContext.h index 38123e1..14745ed 100644 --- a/src/MDMTransitionContext.h +++ b/src/MDMTransitionContext.h @@ -43,6 +43,8 @@ NS_SWIFT_NAME(TransitionContext) */ - (void)transitionDidEnd; +@property(nonatomic, readonly) BOOL wasCancelled; + /** The direction this transition is moving in. */ @@ -84,3 +86,11 @@ NS_SWIFT_NAME(TransitionContext) */ @property(nonatomic, strong, readonly, nullable) UIPresentationController *presentationController; @end + +NS_SWIFT_NAME(InteractiveTransitionContext) +@protocol MDMInteractiveTransitionContext +- (UIPercentDrivenInteractiveTransition *_Nonnull)getPercentIT; +- (void)updatePercent:(CGFloat)percent; +- (void)finishInteractiveTransition; +- (void)cancelInteractiveTransition; +@end diff --git a/src/MDMTransitionController.h b/src/MDMTransitionController.h index c91cc35..e448717 100644 --- a/src/MDMTransitionController.h +++ b/src/MDMTransitionController.h @@ -17,6 +17,7 @@ #import @protocol MDMTransition; +@protocol MDMInteractiveTransition; /** A transition controller is a bridge between UIKit's view controller transitioning APIs and @@ -44,5 +45,4 @@ NS_SWIFT_NAME(TransitionController) This may be non-nil while a transition is active. */ @property(nonatomic, strong, nullable, readonly) id activeTransition; - @end diff --git a/src/UIViewController+TransitionController.h b/src/UIViewController+TransitionController.h index b1f5279..96ae58c 100644 --- a/src/UIViewController+TransitionController.h +++ b/src/UIViewController+TransitionController.h @@ -18,6 +18,7 @@ #import @protocol MDMTransitionController; +@protocol MDMInteractiveTransitionContext; @interface UIViewController (MDMTransitionController) @@ -32,4 +33,5 @@ @property(nonatomic, strong, readonly, nonnull) id mdm_transitionController NS_SWIFT_NAME(transitionController); +@property(nonatomic, strong, nullable) id interactiveTransitionContext; @end diff --git a/src/UIViewController+TransitionController.m b/src/UIViewController+TransitionController.m index 5f9de4a..45d10a9 100644 --- a/src/UIViewController+TransitionController.m +++ b/src/UIViewController+TransitionController.m @@ -24,6 +24,16 @@ @implementation UIViewController (MDMTransitionController) #pragma mark - Public +- (id)interactiveTransitionContext { + //const void *key = [self mdm_transitionControllerKey]; + return objc_getAssociatedObject(self, "interactions"); +} + +- (void)setInteractiveTransitionContext:(id)interactiveTransition { + //const void *key = [self mdm_transitionControllerKey]; + objc_setAssociatedObject(self, "interactions", interactiveTransition, OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + - (id)mdm_transitionController { const void *key = [self mdm_transitionControllerKey]; diff --git a/src/private/MDMPresentationTransitionController.m b/src/private/MDMPresentationTransitionController.m index a34ef26..102ce12 100644 --- a/src/private/MDMPresentationTransitionController.m +++ b/src/private/MDMPresentationTransitionController.m @@ -84,6 +84,14 @@ - (void)setTransition:(id)transition { return _context; } +- (nullable id)interactionControllerForPresentation:(id)animator { + return [self prepareForInteractiveTransition]; +} + +- (nullable id)interactionControllerForDismissal:(id)animator { + return [self prepareForInteractiveTransition]; +} + // Presentation - (UIPresentationController *)presentationControllerForPresentedViewController:(UIViewController *)presented @@ -129,4 +137,36 @@ - (void)prepareForTransitionWithSourceViewController:(nullable UIViewController } } +- (nullable id)prepareForInteractiveTransition { + Boolean isInteractive = false; + + Boolean isInteractiveResponds = false; + Boolean startWithInteractiveResponds = false; + + if ([_transition respondsToSelector:@selector(isInteractive:)]) { + isInteractiveResponds = true; + } else { + return nil; + } + + if ([_transition respondsToSelector:@selector(startWithInteractiveContext:)]) { + startWithInteractiveResponds = true; + } else { + return nil; + } + + if (isInteractiveResponds && startWithInteractiveResponds) { + id interactiveTransition = (id)_transition; + isInteractive = [interactiveTransition isInteractive:_context]; + if (isInteractive) { + [interactiveTransition startWithInteractiveContext:_context]; + } + } + + UIPercentDrivenInteractiveTransition *pdi = [_context getPercentIT]; + // Setting the completion speed to a value close to 1.0 prevents + // the bar from sometimes jumping. + pdi.completionSpeed = 0.933; + return isInteractive == false ? nil : pdi; +} @end diff --git a/src/private/MDMViewControllerTransitionContext.h b/src/private/MDMViewControllerTransitionContext.h index e6f75db..396ebb3 100644 --- a/src/private/MDMViewControllerTransitionContext.h +++ b/src/private/MDMViewControllerTransitionContext.h @@ -21,7 +21,7 @@ @protocol MDMTransition; @protocol MDMViewControllerTransitionContextDelegate; -@interface MDMViewControllerTransitionContext : NSObject +@interface MDMViewControllerTransitionContext : NSObject - (nonnull instancetype)initWithTransition:(nonnull id)transition direction:(MDMTransitionDirection)direction diff --git a/src/private/MDMViewControllerTransitionContext.m b/src/private/MDMViewControllerTransitionContext.m index d39cccf..a99f709 100644 --- a/src/private/MDMViewControllerTransitionContext.m +++ b/src/private/MDMViewControllerTransitionContext.m @@ -20,6 +20,7 @@ @implementation MDMViewControllerTransitionContext { id _transitionContext; + UIPercentDrivenInteractiveTransition *_percent; } @synthesize direction = _direction; @@ -27,7 +28,7 @@ @implementation MDMViewControllerTransitionContext { @synthesize backViewController = _backViewController; @synthesize foreViewController = _foreViewController; @synthesize presentationController = _presentationController; - +@synthesize wasCancelled = _wasCancelled; - (nonnull instancetype)initWithTransition:(nonnull id)transition direction:(MDMTransitionDirection)direction sourceViewController:(nullable UIViewController *)sourceViewController @@ -44,6 +45,7 @@ - (nonnull instancetype)initWithTransition:(nonnull id)transition _presentationController = presentationController; _transition = [self fallbackForTransition:_transition]; + _percent = [[UIPercentDrivenInteractiveTransition alloc] init]; } if (!_transition) { return nil; @@ -82,7 +84,14 @@ - (UIView *)containerView { } - (void)transitionDidEnd { - [_transitionContext completeTransition:true]; + BOOL wasCanceled = [_transitionContext transitionWasCancelled]; + if (wasCanceled) { + _wasCancelled = false; + [_transitionContext completeTransition:false]; + } else { + _wasCancelled = true; + [_transitionContext completeTransition:true]; + } _transition = nil; @@ -173,4 +182,20 @@ - (void)anticipateOnlyExplicitAnimations { return transition; } +- (UIPercentDrivenInteractiveTransition *_Nonnull)getPercentIT { + return _percent; +} + +- (void)updatePercent:(CGFloat)percent { + [_percent updateInteractiveTransition:percent]; +} + +- (void)finishInteractiveTransition { + [_percent finishInteractiveTransition]; +} + +- (void)cancelInteractiveTransition { + [_percent cancelInteractiveTransition]; +} + @end