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 <UIKit/UIKit.h>
 
 @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 <NSObject>
+- (Boolean)isInteractive:(nonnull id<MDMTransitionContext>)context;
+- (void)startWithInteractiveContext:(nonnull id<MDMInteractiveTransitionContext>)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 <MDMTransitionContext>
+- (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 <Foundation/Foundation.h>
 
 @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<MDMTransition> 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 <UIKit/UIKit.h>
 
 @protocol MDMTransitionController;
+@protocol MDMInteractiveTransitionContext;
 
 @interface UIViewController (MDMTransitionController)
 
@@ -32,4 +33,5 @@
 @property(nonatomic, strong, readonly, nonnull) id<MDMTransitionController> mdm_transitionController
     NS_SWIFT_NAME(transitionController);
 
+@property(nonatomic, strong, nullable) id<MDMInteractiveTransitionContext> 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<MDMInteractiveTransition>)interactiveTransitionContext {
+  //const void *key = [self mdm_transitionControllerKey];
+  return objc_getAssociatedObject(self, "interactions");
+}
+
+- (void)setInteractiveTransitionContext:(id<MDMInteractiveTransition>)interactiveTransition {
+  //const void *key = [self mdm_transitionControllerKey];
+  objc_setAssociatedObject(self, "interactions", interactiveTransition, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+}
+
 - (id<MDMTransitionController>)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<MDMTransition>)transition {
   return _context;
 }
 
+- (nullable id<UIViewControllerInteractiveTransitioning>)interactionControllerForPresentation:(id<UIViewControllerAnimatedTransitioning>)animator {
+  return [self prepareForInteractiveTransition];
+}
+
+- (nullable id<UIViewControllerInteractiveTransitioning>)interactionControllerForDismissal:(id<UIViewControllerAnimatedTransitioning>)animator {
+  return [self prepareForInteractiveTransition];
+}
+
 // Presentation
 
 - (UIPresentationController *)presentationControllerForPresentedViewController:(UIViewController *)presented
@@ -129,4 +137,36 @@ - (void)prepareForTransitionWithSourceViewController:(nullable UIViewController
   }
 }
 
+- (nullable id<UIViewControllerInteractiveTransitioning>)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<MDMInteractiveTransition> interactiveTransition = (id<MDMInteractiveTransition>)_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 <MDMTransitionContext, UIViewControllerAnimatedTransitioning>
+@interface MDMViewControllerTransitionContext : NSObject <MDMTransitionContext, MDMInteractiveTransitionContext, UIViewControllerAnimatedTransitioning>
 
 - (nonnull instancetype)initWithTransition:(nonnull id<MDMTransition>)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<UIViewControllerContextTransitioning> _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<MDMTransition>)transition
                                  direction:(MDMTransitionDirection)direction
                       sourceViewController:(nullable UIViewController *)sourceViewController
@@ -44,6 +45,7 @@ - (nonnull instancetype)initWithTransition:(nonnull id<MDMTransition>)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