WIP.
diff --git a/examples/CustomPresentationExample.swift b/examples/CustomPresentationExample.swift
index c3d3b45..3f1189d 100644
--- a/examples/CustomPresentationExample.swift
+++ b/examples/CustomPresentationExample.swift
@@ -250,10 +250,37 @@
   }
 }
 
+private final class DragToDismissInteractionController: NSObject, TransitionInteractionController {
+  let gestureRecognizer = UIPanGestureRecognizer()
+  let driver = UIPercentDrivenInteractiveTransition()
+  var associatedViewController: UIViewController?
+
+  override init() {
+    super.init()
+
+    self.gestureRecognizer.addTarget(self, action: #selector(didPan(_:)))
+  }
+
+  func interactionCoordinatorForTransition(with context: TransitionContext) -> UIViewControllerInteractiveTransitioning {
+    return driver
+  }
+
+  func didPan(_ gestureRecognizer: UIPanGestureRecognizer) {
+    switch gestureRecognizer.state {
+    case .began:
+      associatedViewController?.dismiss(animated: true)
+    default: break
+    }
+  }
+}
+
 extension CustomPresentationExampleViewController {
   override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
     let modal = ModalViewController()
     modal.transitionController.transition = transitions[indexPath.row].transition
+    let interactionController = DragToDismissInteractionController()
+    modal.view.addGestureRecognizer(interactionController.gestureRecognizer)
+    modal.transitionController.interactionController = interactionController
     showDetailViewController(modal, sender: self)
   }
 }
diff --git a/src/MDMTransition.h b/src/MDMTransition.h
index 3122955..11b0355 100644
--- a/src/MDMTransition.h
+++ b/src/MDMTransition.h
@@ -115,8 +115,3 @@
 
 @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 14745ed..4314663 100644
--- a/src/MDMTransitionContext.h
+++ b/src/MDMTransitionContext.h
@@ -87,10 +87,3 @@
 @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 e448717..bc54406 100644
--- a/src/MDMTransitionController.h
+++ b/src/MDMTransitionController.h
@@ -17,7 +17,7 @@
 #import <Foundation/Foundation.h>
 
 @protocol MDMTransition;
-@protocol MDMInteractiveTransition;
+@protocol MDMTransitionInteractionController;
 
 /**
  A transition controller is a bridge between UIKit's view controller transitioning APIs and
@@ -45,4 +45,10 @@
  This may be non-nil while a transition is active.
  */
 @property(nonatomic, strong, nullable, readonly) id<MDMTransition> activeTransition;
+
+/**
+ The interaction controller that will govern any interactions during the transition.
+ */
+@property(nonatomic, strong, nullable) id<MDMTransitionInteractionController> interactionController;
+
 @end
diff --git a/src/MDMTransitionInteractionController.h b/src/MDMTransitionInteractionController.h
new file mode 100644
index 0000000..89a2bbc
--- /dev/null
+++ b/src/MDMTransitionInteractionController.h
@@ -0,0 +1,30 @@
+/*
+ Copyright 2017-present The Material Motion Authors. All Rights Reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+
+@protocol MDMTransitionContext;
+
+/**
+ A transition interaction controller is able to control the progress of a transition, often in
+ reaction to gesture recognition.
+ */
+NS_SWIFT_NAME(TransitionInteractionController)
+@protocol MDMTransitionInteractionController <NSObject>
+
+@property(nonatomic, weak, nullable) UIViewController *associatedViewController;
+
+- (nonnull id<UIViewControllerInteractiveTransitioning>)interactionCoordinatorForTransitionWithContext:(nonnull id<MDMTransitionContext>)context;
+
+@end
diff --git a/src/UIViewController+TransitionController.h b/src/UIViewController+TransitionController.h
index 96ae58c..d4fe196 100644
--- a/src/UIViewController+TransitionController.h
+++ b/src/UIViewController+TransitionController.h
@@ -33,5 +33,4 @@
 @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 45d10a9..5f9de4a 100644
--- a/src/UIViewController+TransitionController.m
+++ b/src/UIViewController+TransitionController.m
@@ -24,16 +24,6 @@
 
 #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 102ce12..6fa87fa 100644
--- a/src/private/MDMPresentationTransitionController.m
+++ b/src/private/MDMPresentationTransitionController.m
@@ -17,6 +17,7 @@
 #import "MDMPresentationTransitionController.h"
 
 #import "MDMTransition.h"
+#import "MDMTransitionInteractionController.h"
 #import "MDMViewControllerTransitionContext.h"
 
 @interface MDMPresentationTransitionController () <UIViewControllerTransitioningDelegate, MDMViewControllerTransitionContextDelegate>
@@ -34,6 +35,7 @@
 }
 
 @synthesize transition = _transition;
+@synthesize interactionController = _interactionController;
 
 - (nonnull instancetype)initWithViewController:(nonnull UIViewController *)viewController {
   self = [super init];
@@ -56,6 +58,12 @@
   }
 }
 
+- (void)setInteractionController:(id<MDMTransitionInteractionController>)interactionController {
+  _interactionController = interactionController;
+
+  [_interactionController setAssociatedViewController:_associatedViewController];
+}
+
 - (id<MDMTransition>)activeTransition {
   return _context.transition;
 }
@@ -85,11 +93,13 @@
 }
 
 - (nullable id<UIViewControllerInteractiveTransitioning>)interactionControllerForPresentation:(id<UIViewControllerAnimatedTransitioning>)animator {
-  return [self prepareForInteractiveTransition];
+  [self prepareForInteractiveTransition];
+  return [_interactionController interactionCoordinatorForTransitionWithContext:_context];
 }
 
 - (nullable id<UIViewControllerInteractiveTransitioning>)interactionControllerForDismissal:(id<UIViewControllerAnimatedTransitioning>)animator {
-  return [self prepareForInteractiveTransition];
+  [self prepareForInteractiveTransition];
+  return [_interactionController interactionCoordinatorForTransitionWithContext:_context];
 }
 
 // Presentation
@@ -137,36 +147,8 @@
   }
 }
 
-- (nullable id<UIViewControllerInteractiveTransitioning>)prepareForInteractiveTransition {
-  Boolean isInteractive = false;
+- (void)prepareForInteractiveTransition {
 
-  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 396ebb3..e6f75db 100644
--- a/src/private/MDMViewControllerTransitionContext.h
+++ b/src/private/MDMViewControllerTransitionContext.h
@@ -21,7 +21,7 @@
 @protocol MDMTransition;
 @protocol MDMViewControllerTransitionContextDelegate;
 
-@interface MDMViewControllerTransitionContext : NSObject <MDMTransitionContext, MDMInteractiveTransitionContext, UIViewControllerAnimatedTransitioning>
+@interface MDMViewControllerTransitionContext : NSObject <MDMTransitionContext, UIViewControllerAnimatedTransitioning>
 
 - (nonnull instancetype)initWithTransition:(nonnull id<MDMTransition>)transition
                                  direction:(MDMTransitionDirection)direction
diff --git a/src/private/MDMViewControllerTransitionContext.m b/src/private/MDMViewControllerTransitionContext.m
index 7900270..d6a5c90 100644
--- a/src/private/MDMViewControllerTransitionContext.m
+++ b/src/private/MDMViewControllerTransitionContext.m
@@ -20,7 +20,6 @@
 
 @implementation MDMViewControllerTransitionContext {
   id<UIViewControllerContextTransitioning> _transitionContext;
-  UIPercentDrivenInteractiveTransition *_percent;
 }
 
 @synthesize direction = _direction;
@@ -29,6 +28,7 @@
 @synthesize foreViewController = _foreViewController;
 @synthesize presentationController = _presentationController;
 @synthesize wasCancelled = _wasCancelled;
+
 - (nonnull instancetype)initWithTransition:(nonnull id<MDMTransition>)transition
                                  direction:(MDMTransitionDirection)direction
                       sourceViewController:(nullable UIViewController *)sourceViewController
@@ -48,7 +48,6 @@
     if (!_transition) {
       return nil;
     }
-    _percent = [[UIPercentDrivenInteractiveTransition alloc] init];
   }
   return self;
 }
@@ -69,10 +68,6 @@
   [self initiateTransition];
 }
 
-// TODO(featherless): Implement interactive transitioning. Need to implement
-// UIViewControllerInteractiveTransitioning here and isInteractive and interactionController* in
-// MDMPresentationTransitionController.
-
 #pragma mark - MDMTransitionContext
 
 - (NSTimeInterval)duration {
@@ -182,20 +177,4 @@
   return transition;
 }
 
-- (UIPercentDrivenInteractiveTransition *_Nonnull)getPercentIT {
-  return _percent;
-}
-
-- (void)updatePercent:(CGFloat)percent {
-  [_percent updateInteractiveTransition:percent];
-}
-
-- (void)finishInteractiveTransition {
-  [_percent finishInteractiveTransition];
-}
-
-- (void)cancelInteractiveTransition {
-  [_percent cancelInteractiveTransition];
-}
-
 @end