Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save guodong000/60f906a61af027719c35 to your computer and use it in GitHub Desktop.
Save guodong000/60f906a61af027719c35 to your computer and use it in GitHub Desktop.
iOS 7 screen edge gesture swipe from right to left (similar to edge swiping from left to right) on UINavigationController. *only* the edge swipe uses the custom transition; everything else uses default behaviors.
//
// SlideAnimatedTransitioning.h
// SwipeLeft
//
// Created by Visnu on 4/14/14.
// Copyright (c) 2014 Visnu Pitiyanuvath. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface SlideAnimatedTransitioning : NSObject <UIViewControllerAnimatedTransitioning>
@end
//
// SlideAnimatedTransitioning.m
// SwipeLeft
//
// Created by Visnu on 4/14/14.
// Copyright (c) 2014 Visnu Pitiyanuvath. All rights reserved.
//
#import "SlideAnimatedTransitioning.h"
// Tries to duplicate the default iOS 7 slide transition for UINavigationController
@implementation SlideAnimatedTransitioning
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
UIView *containerView = [transitionContext containerView],
*fromView = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey].view,
*toView = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey].view;
CGFloat width = containerView.frame.size.width;
CGRect offsetLeft = fromView.frame; offsetLeft.origin.x = -width/3;
CGRect offscreenRight = toView.frame; offscreenRight.origin.x = width;
toView.frame = offscreenRight;
toView.layer.shadowRadius = 5;
toView.layer.shadowOpacity = 0.4;
[containerView addSubview:toView];
[UIView animateWithDuration:[self transitionDuration:transitionContext] delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
toView.frame = fromView.frame;
fromView.frame = offsetLeft;
fromView.layer.opacity = 0.9;
} completion:^(BOOL finished) {
fromView.layer.opacity = 1;
toView.layer.shadowOpacity = 0;
// when cancelling or completing the animation, ios simulator seems to sometimes flash black backgrounds during the animation. on devices, this doesn't seem to happen though.
// containerView.backgroundColor = [UIColor whiteColor];
[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
}];
}
- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext
{
return 0.2;
}
@end
//
// ViewController.m
// SwipeLeft
//
// Created by Visnu on 4/10/14.
// Copyright (c) 2014 Visnu Pitiyanuvath. All rights reserved.
//
#import "ViewController.h"
#import "SlideAnimatedTransitioning.h"
@interface ViewController ()
@property UIScreenEdgePanGestureRecognizer *edgePanGestureRecognizer;
@property UIPercentDrivenInteractiveTransition *percentDrivenInteractiveTransition;
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Setup a screen edge pan gesture recognizer to trigger from the right edge of the screen.
self.edgePanGestureRecognizer = [[UIScreenEdgePanGestureRecognizer alloc] initWithTarget:self action:@selector(handleScreenEdgePanGesture:)];
self.edgePanGestureRecognizer.edges = UIRectEdgeRight;
[self.view addGestureRecognizer:self.edgePanGestureRecognizer];
}
- (void)handleScreenEdgePanGesture:(UIScreenEdgePanGestureRecognizer *)sender
{
CGFloat width = self.view.frame.size.width,
percent = MAX(-[sender translationInView:self.view].x, 0) / width;
switch (sender.state) {
case UIGestureRecognizerStateBegan:
// Configure the navigation controller to return the custom (interactive/animated) transition.
self.navigationController.delegate = self;
// Trigger a segue (or push another view controller, whatevs you want).
[self performSegueWithIdentifier:@"next" sender:sender];
break;
case UIGestureRecognizerStateChanged:
// Update the transition using a UIPercentDrivenInteractiveTransition.
[self.percentDrivenInteractiveTransition updateInteractiveTransition:percent];
break;
case UIGestureRecognizerStateEnded:
// Cancel or finish depending on how the gesture ended.
if (percent > 0.5 || fabs([sender velocityInView:self.view].x) > 1000)
[self.percentDrivenInteractiveTransition finishInteractiveTransition];
else
[self.percentDrivenInteractiveTransition cancelInteractiveTransition];
break;
default:
NSLog(@"unhandled state for gesture=%@", sender);
}
}
- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC
{
// Have to return a custom transition here in order for the navigation controller to ask about the interactive stuff below. The SlideAnimatedTransitioning just tries to duplicate the default transition as much as possible.
return [SlideAnimatedTransitioning new];
}
- (id<UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController interactionControllerForAnimationController:(id<UIViewControllerAnimatedTransitioning>)animationController
{
// Unset the delegate so that all other types of transitions (back, normal animated push not initiated by a gesture) get the default behavior.
self.navigationController.delegate = nil;
if (self.edgePanGestureRecognizer.state == UIGestureRecognizerStateBegan) {
self.percentDrivenInteractiveTransition = [UIPercentDrivenInteractiveTransition new];
self.percentDrivenInteractiveTransition.completionCurve = UIViewAnimationOptionCurveEaseOut;
} else {
self.percentDrivenInteractiveTransition = nil;
}
return self.percentDrivenInteractiveTransition;
}
@end
@guodong000
Copy link
Author

SlideAnimatedTransitioning

https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIViewControllerAnimatedTransitioning_Protocol/

Adopt the UIViewControllerAnimatedTransitioning protocol in objects that implement the animations for a custom view controller transition.

The animations you create using this protocol must not be interactive.

To add user interaction to a view controller transition, you must use an animator object together with an interactive animator object—a custom object that adopts the UIViewControllerInteractiveTransitioning protocol.

UINavigatorControllerDelegate

UIPercentDrivenInteractiveTransition

流程

UINavigationControll 通过 delegate 获取 UIViewControllerAnimatedTransitioning 和 UIViewControllerInteractiveTransitioning;用户手势通过 UIScreenEdgePanGestureRecognizer 进行处理,并根据手势状态动态修改 UIViewControllerInteractiveTransitioning,以达到可交互的切换动画。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment