Skip to content

Instantly share code, notes, and snippets.

@andkon
Created June 22, 2014 03:19
Show Gist options
  • Save andkon/72c7769e853bbb379e4d to your computer and use it in GitHub Desktop.
Save andkon/72c7769e853bbb379e4d to your computer and use it in GitHub Desktop.
Interactive Transitions
@interface InteractiveTransition.h : NSObject <UIViewControllerAnimatedTransitioning>
@end
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
CGRect initialFrame = fromVC.view.frame;
CGRect finalFrame = CGRectMake(
initialFrame.origin.x,
initialFrame.size.height + 16,
initialFrame.size.width,
initialFrame.size.height
);
// use this option to make it stick under the user's finger:
UIViewAnimationOptions *opts = UIViewAnimationOptionCurveLinear;
[UIView animateWithDuration:1.0
delay:0.0
options:opts
animations:^{
fromVC.view.frame = finalFrame;
}
completion:^(BOOL finished) {
[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
}
];
}
- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext
{
// useless but necessary
return 1.0f;
}
@interface RootVC : UIViewController <UIViewControllerTransitioningDelegate>
@property (strong, nonatomic) UIPercentDrivenInteractiveTransition *myInteractiveDismissal;
@proprety (strong, nonatomic) BOOL interactive;
@end
#import "InteractiveTransition.h"
#import "NonInteractiveTransition.h"
-(void)openButtonPressed
{
ModalVC *modalVC = [[ModalVC alloc] init];
modalVC.modalPresentationStyle = UIModalPresentationCustom;
modalVC.transitioningDelegate = self;
[self presentViewController:modalVC
animated:YES
completion:^{
UIPanGestureRecognizer *gesture;
gesture = [[UIPanGestureRecognizer alloc] init];
// This method gets called in RootVC:
[gesture addTarget:self action:@selector(handleGesture:)];
// The gesture object gets added to modalVC.view:
[loginVC.view addGestureRecognizer:gesture];
}
];
}
- (void)handleGesture:(UIPanGestureRecognizer *)gesture
{
switch (gesture.state) {
case UIGestureRecognizerStateBegan:{
self.interactive = YES;
[self dismissViewControllerAnimated:YES completion:^{
self.interactive = NO;
}];
break;
}
case UIGestureRecognizerStateChanged:{
// Gives us the transition context's container view
UIView *view = gesture.view.superview;
// This gets us the point of where the gesture is in view:
CGPoint translation = [gesture translationInView:view];
CGFloat percentTransitioned = (translation.y / (CGRectGetHeight(view.frame)));
[self.myInteractiveDismissal updateInteractiveTransition:percentTransitioned];
break;
}
case UIGestureRecognizerStateEnded:{
if (self.myInteractiveDismissal.percentComplete > 0.25) {
[self.myInteractiveDismissal finishInteractiveTransition];
} else {
[self.myInteractiveDismissal cancelInteractiveTransition];
}
break;
}
case UIGestureRecognizerStateCancelled:{
[self.myInteractiveDismissal cancelInteractiveTransition];
}
}
}
- (id <UIViewControllerInteractiveTransitioning>)interactionControllerForDismissal:(id<UIViewControllerAnimatedTransitioning>)animator
{
// In animated transitions, we had to create out own classes (eg BouncyTransition) to make the
// transition work. In this case, we just use UIPercentDrivenInteractiveTransition.
if (self.interactive) {
self.myInteractiveDismissal = [[UIPercentDrivenInteractiveTransition alloc] init];
return self.myInteractiveDismissal;
}
return nil;
}
// You also need the usual <UIViewControllerTransitioningDelegate> stuff:
- (id <UIViewControllerAnimatedTransitioning>) animationControllerForDismissedController:(UIViewController *)dismissed
{
id<UIViewControllerAnimatedTransitioning> transition;
if (self.interactive) {
transition = [[InteractiveTransition alloc] init];
} else {
transition = [[NonInteractiveTransition alloc] init];
}
return transition;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment