I have a simple interactive animation : the same as the iOS transition between pages. But when the transition is finished or cancelled, sometimes, it go back to an old position, like a back effect. Here's my code, you can test it to see what i mean. How can I fix it ? Also, does a better method exist to make an interactive transition between ViewControllers ?
Thx
NavigationControllerDelegate.m
#import "NavigationControllerDelegate.h"
#import "Animator.h"
#interface NavigationControllerDelegate ()
#property (weak, nonatomic) IBOutlet UINavigationController *navigationController;
#property (strong, nonatomic) Animator* animator;
#property (strong, nonatomic) UIPercentDrivenInteractiveTransition* interactionController;
#end
#implementation NavigationControllerDelegate
- (void)awakeFromNib
{
UIPanGestureRecognizer* panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(pan:)];
[self.navigationController.view addGestureRecognizer:panRecognizer];
self.animator = [Animator new];
}
- (void)pan:(UIPanGestureRecognizer*)recognizer
{
UIView* view = self.navigationController.view;
if (recognizer.state == UIGestureRecognizerStateBegan) {
CGPoint location = [recognizer locationInView:view];
if (location.x < CGRectGetMidX(view.bounds) && self.navigationController.viewControllers.count > 1) { // left half
self.interactionController = [UIPercentDrivenInteractiveTransition new];
[self.navigationController popViewControllerAnimated:YES];
}
} else if (recognizer.state == UIGestureRecognizerStateChanged) {
CGPoint translation = [recognizer translationInView:view];
CGFloat d = fabs(translation.x / CGRectGetWidth(view.bounds));
[self.interactionController updateInteractiveTransition:d];
} else if (recognizer.state == UIGestureRecognizerStateEnded) {
CGPoint translation = [recognizer translationInView:view];
CGFloat d = (translation.x / CGRectGetWidth(view.bounds));
if (d > 0.5) {
[self.interactionController finishInteractiveTransition];
} else {
[self.interactionController cancelInteractiveTransition];
}
self.interactionController = nil;
}
}
- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC
{
if (operation == UINavigationControllerOperationPop) {
return self.animator;
}
return nil;
}
- (id<UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController interactionControllerForAnimationController:(id<UIViewControllerAnimatedTransitioning>)animationController
{
return self.interactionController;
}
#end
Animator.m
#import "Animator.h"
#implementation Animator
- (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext
{
return 1;
}
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
CGRect screenBounds = [[UIScreen mainScreen] bounds];
UIViewController* toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
UIViewController* fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
[[transitionContext containerView] addSubview:toViewController.view];
toViewController.view.frame = CGRectMake(-screenBounds.size.width, 0, screenBounds.size.width, screenBounds.size.height);
[UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
toViewController.view.frame = CGRectMake(0, 0, screenBounds.size.width, screenBounds.size.height);
fromViewController.view.frame = CGRectMake(screenBounds.size.width, 0, screenBounds.size.width, screenBounds.size.height);
} completion:^(BOOL finished) {
[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
}];
}
#end
Related
I have a Custom Transition, I apply it in a ViewController which complies with UIViewControllerTransitioningDelegate protocol. My transition works ok. But when i change UIViewControllerTransitioningDelegate protocol to UINavigationControllerDelegate protocol, it works strangely.
The function i want to realize
Strange presentation with only one piece of toView
MyTransitioning:
#import "MyTransitioning.h"
#define PARTS_COUNT 4
#interface MyTransitioning()
#property (nonatomic) CGFloat partWidth;
#property (nonatomic) CGFloat partHeight;
#end
#implementation MyTransitioning
-(NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext
{
return 1.0;
}
-(void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
UIViewController* fromCtrl = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController* toCtrl = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
UIView* fromView = fromCtrl.view;
UIView* toView = toCtrl.view;
UIView* container = [transitionContext containerView];
CATransform3D transform = container.layer.transform;
transform.m34 = -0.01;
[container.layer setSublayerTransform:transform];
NSArray<UIView*>* fromViewParts = [self spliteView:fromView];
NSArray<UIView*>* toViewParts = [self spliteView:toView];
[self addViews:toViewParts ToContainer:container isFromView:NO];
[self addViews:fromViewParts ToContainer:container isFromView:YES];
[fromView removeFromSuperview];
[UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^
{
[self strechViews:toViewParts];
[self compressViews:fromViewParts ToLeft:YES];
} completion:^(BOOL finished)
{
if (!finished)
{
NSLog(#"not finish");
}
[self removeViewsfromSuper:fromViewParts];
[self removeViewsfromSuper:toViewParts];
[container addSubview:toView];
[transitionContext completeTransition:!transitionContext.transitionWasCancelled];
}];
}
-(NSArray*)spliteView:(UIView*)view
{
self.partWidth = view.bounds.size.width / PARTS_COUNT;
self.partHeight = view.bounds.size.height;
CGRect region = CGRectMake(0, 0, self.partWidth, self.partHeight);
NSMutableArray<UIView*>* viewParts = [NSMutableArray array];
for (int i = 0; i < PARTS_COUNT; i++)
{
region.origin.x =self.partWidth * i;
UIView* partView = [view resizableSnapshotViewFromRect:region afterScreenUpdates:YES withCapInsets:UIEdgeInsetsZero];
[viewParts addObject:partView];
partView.frame = region;
}
return viewParts;
}
-(void)addViews:(NSArray<UIView*>*)views ToContainer:(UIView*)container isFromView:(BOOL)isFromView
{
isFromView ? [self strechViews:views] : [self compressViews:views ToLeft:NO];
for (UIView* view in views)
{
[container addSubview:view];
}
}
-(void)compressViews:(NSArray<UIView*>*)views ToLeft:(BOOL)toLeft
{
CGFloat x = toLeft ? 0 : self.partWidth * 4;
int isClockWise = -1;
CGPoint position = CGPointMake(x, self.partHeight / 2);
for (UIView* view in views) {
isClockWise *= -1;
view.layer.anchorPoint = CGPointMake(0.5 - isClockWise * 0.5, 0.5);
view.layer.position = position;
view.layer.transform = CATransform3DMakeRotation(M_PI_2 * isClockWise, 0, 1, 0);
}
}
-(void)strechViews:(NSArray<UIView*>*)views
{
int isClockWise = -1;
for (UIView* view in views)
{
isClockWise *= -1;
view.layer.anchorPoint = CGPointMake(0.5 - isClockWise * 0.5, 0.5);
NSLog(#"%#",NSStringFromCGPoint(view.layer.anchorPoint));
CGPoint position = view.layer.position;
position.x = self.partWidth * [views indexOfObject:view] + (isClockWise == 1 ? 0 : self.partWidth);
view.layer.position = position;
view.layer.transform = CATransform3DIdentity;
NSLog(#"%#",NSStringFromCGRect(view.frame));
}
}
-(void)removeViewsfromSuper:(NSArray<UIView*>*)views
{
for (UIView* view in views)
{
[view removeFromSuperview];
}
}
#end
ViewController:
#import "ViewController.h"
#import "MyTransitioning.h"
#import "SecondController.h"
#interface ViewController ()<UINavigationControllerDelegate>
//#interface ViewController ()<UIViewControllerTransitioningDelegate>
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
//-(id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source
//{
// return [MyTransitioning new];
//}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
self.navigationController.delegate = self;
// SecondController* ctrl = [segue destinationViewController];
// ctrl.transitioningDelegate = self;
}
-(id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC
{
if (operation == UINavigationControllerOperationPush) {
return [MyTransitioning new];
}
return nil;
}
#end
If your question is difference between PresentViewController and Push,pop view controller then,
PushViewController
Push View controller is a property of the Navigation controller. When you want to move forward from one controller to other you use this.
PopViewController
Pop view controller is also a property of the navigation controller. When you want to go backward in navigation stack you this.
PresentViewController / Model View controller
Present view controller is not a property of the navigation controller. To perform either push/pop your controller should be subclassed with UINavigationController either directly or indirectly. Whereas to present view controller you don't need to have reference of navigation controller, directly you call [self presentViewController..]
I'm using ECSlidingViewController in my application to display left menu.
Is there are any way to make main view controller 'darker' when it's moved and left menu is displayed?
Thanks.
I solved this issue.
Just get some classes from example and changed it:
CPSlidingAnimationController:
#import "CPSlidingAnimationController.h"
#import "ECSlidingAnimationController.h"
#import "ECSlidingConstants.h"
#interface CPSlidingAnimationController ()
#property (nonatomic, copy) void (^coordinatorAnimations)(id<UIViewControllerTransitionCoordinatorContext>context);
#property (nonatomic, copy) void (^coordinatorCompletion)(id<UIViewControllerTransitionCoordinatorContext>context);
#end
#implementation CPSlidingAnimationController
#synthesize transition, animationFinishCallback;
#pragma mark - UIViewControllerAnimatedTransitioning
- (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext {
return 0.25;
}
- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext {
UIViewController *topViewController = [transitionContext viewControllerForKey:ECTransitionContextTopViewControllerKey];
UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
UIView *containerView = [transitionContext containerView];
CGRect topViewInitialFrame = [transitionContext initialFrameForViewController:topViewController];
CGRect topViewFinalFrame = [transitionContext finalFrameForViewController:topViewController];
topViewController.view.frame = topViewInitialFrame;
if (topViewController != toViewController) {
CGRect toViewFinalFrame = [transitionContext finalFrameForViewController:toViewController];
toViewController.view.frame = toViewFinalFrame;
[containerView insertSubview:toViewController.view belowSubview:topViewController.view];
}
NSTimeInterval duration = [self transitionDuration:transitionContext];
[UIView animateWithDuration:duration
animations:^{
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
if (self.coordinatorAnimations) self.coordinatorAnimations((id<UIViewControllerTransitionCoordinatorContext>)transitionContext);
topViewController.view.frame = topViewFinalFrame;
} completion:^(BOOL finished) {
if ([transitionContext transitionWasCancelled]) {
topViewController.view.frame = [transitionContext initialFrameForViewController:topViewController];
}
if (self.coordinatorCompletion) self.coordinatorCompletion((id<UIViewControllerTransitionCoordinatorContext>)transitionContext);
[transitionContext completeTransition:finished];
if (transition) {
if ([(NSObject*) transition respondsToSelector:animationFinishCallback]) {
[transition performSelector:animationFinishCallback];
}
}
}];
}
#end
MEDynamicTransition.h:
#import "MEDynamicTransition.h"
#import "CPSlidingAnimationController.h"
#interface MEDynamicTransition () {
UIVisualEffectView * effectView;
}
#property (nonatomic, strong) CPSlidingAnimationController * defaultAnimationController;
#property (nonatomic, strong) NSMutableArray *leftEdgeQueue;
#property (nonatomic, assign) id<UIViewControllerContextTransitioning> transitionContext;
#property (nonatomic, strong) UIDynamicAnimator *animator;
#property (nonatomic, strong) UICollisionBehavior *collisionBehavior;
#property (nonatomic, strong) UIGravityBehavior *gravityBehavior;
#property (nonatomic, strong) UIPushBehavior *pushBehavior;
#property (nonatomic, strong) UIDynamicItemBehavior *topViewBehavior;
#property (nonatomic, strong) UIDynamicBehavior *compositeBehavior;
#property (nonatomic, assign) BOOL positiveLeftToRight;
#property (nonatomic, assign) BOOL isPanningRight;
#property (nonatomic, assign) BOOL isInteractive;
#property (nonatomic, assign) CGFloat fullWidth;
#property (nonatomic, assign) CGRect initialTopViewFrame;
#end
#implementation MEDynamicTransition
#pragma mark - ECSlidingViewControllerDelegate
- (id<UIViewControllerAnimatedTransitioning>)slidingViewController:(ECSlidingViewController *)slidingViewController
animationControllerForOperation:(ECSlidingViewControllerOperation)operation
topViewController:(UIViewController *)topViewController {
return self.defaultAnimationController;
}
- (id<UIViewControllerInteractiveTransitioning>)slidingViewController:(ECSlidingViewController *)slidingViewController
interactionControllerForAnimationController:(id <UIViewControllerAnimatedTransitioning>)animationController {
self.slidingViewController = slidingViewController;
return self;
}
#pragma mark - Properties
- (CPSlidingAnimationController *)defaultAnimationController {
if (_defaultAnimationController) return _defaultAnimationController;
_defaultAnimationController = [[CPSlidingAnimationController alloc] init];
_defaultAnimationController.transition = self;
_defaultAnimationController.animationFinishCallback = #selector(blurControl);
return _defaultAnimationController;
}
- (NSMutableArray *)leftEdgeQueue {
if (_leftEdgeQueue) return _leftEdgeQueue;
_leftEdgeQueue = [NSMutableArray arrayWithCapacity:5];
return _leftEdgeQueue;
}
- (UIDynamicAnimator *)animator {
if (_animator) return _animator;
_animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.slidingViewController.view];
_animator.delegate = self;
[_animator updateItemUsingCurrentState:self.slidingViewController.topViewController.view];
return _animator;
}
- (UICollisionBehavior *)collisionBehavior {
if (_collisionBehavior) return _collisionBehavior;
_collisionBehavior = [[UICollisionBehavior alloc] initWithItems:#[self.slidingViewController.topViewController.view]];
CGFloat containerHeight = self.slidingViewController.view.bounds.size.height;
CGFloat containerWidth = self.slidingViewController.view.bounds.size.width;
CGFloat revealAmount = self.slidingViewController.anchorRightRevealAmount;
[_collisionBehavior addBoundaryWithIdentifier:#"LeftEdge" fromPoint:CGPointMake(-1, 0) toPoint:CGPointMake(-1, containerHeight)];
[_collisionBehavior addBoundaryWithIdentifier:#"RightEdge" fromPoint:CGPointMake(revealAmount + containerWidth + 1, 0) toPoint:CGPointMake(revealAmount + containerWidth + 1, containerHeight)];
return _collisionBehavior;
}
- (UIGravityBehavior *)gravityBehavior {
if (_gravityBehavior) return _gravityBehavior;
_gravityBehavior = [[UIGravityBehavior alloc] initWithItems:#[self.slidingViewController.topViewController.view]];
return _gravityBehavior;
}
- (UIPushBehavior *)pushBehavior {
if (_pushBehavior) return _pushBehavior;
_pushBehavior = [[UIPushBehavior alloc] initWithItems:#[self.slidingViewController.topViewController.view] mode:UIPushBehaviorModeInstantaneous];
return _pushBehavior;
}
- (UIDynamicItemBehavior *)topViewBehavior {
if (_topViewBehavior) return _topViewBehavior;
UIView *topView = self.slidingViewController.topViewController.view;
_topViewBehavior = [[UIDynamicItemBehavior alloc] initWithItems:#[topView]];
// the density ranges from 1 to 5 for iPad to iPhone
_topViewBehavior.density = 908800 / (topView.bounds.size.width * topView.bounds.size.height);
_topViewBehavior.elasticity = 0;
_topViewBehavior.resistance = 1;
return _topViewBehavior;
}
- (UIDynamicBehavior *)compositeBehavior {
if (_compositeBehavior) return _compositeBehavior;
_compositeBehavior = [[UIDynamicBehavior alloc] init];
[_compositeBehavior addChildBehavior:self.collisionBehavior];
[_compositeBehavior addChildBehavior:self.gravityBehavior];
[_compositeBehavior addChildBehavior:self.pushBehavior];
[_compositeBehavior addChildBehavior:self.topViewBehavior];
__weak typeof(self)weakSelf = self;
_compositeBehavior.action = ^{
// stop the dynamic animation when the value of the left edge is the same 5 times in a row.
NSNumber *leftEdge = [NSNumber numberWithFloat:weakSelf.slidingViewController.topViewController.view.frame.origin.x];
[weakSelf.leftEdgeQueue insertObject:leftEdge atIndex:0];
if (weakSelf.leftEdgeQueue.count == 6) [weakSelf.leftEdgeQueue removeLastObject];
if (weakSelf.leftEdgeQueue.count == 5 &&
((NSArray *)[weakSelf.leftEdgeQueue valueForKeyPath:#"#distinctUnionOfObjects.self"]).count == 1) {
[weakSelf.animator removeAllBehaviors];
}
};
return _compositeBehavior;
}
#pragma mark - UIViewControllerInteractiveTransitioning
- (void)startInteractiveTransition:(id<UIViewControllerContextTransitioning>)transitionContext {
self.transitionContext = transitionContext;
UIViewController *topViewController = [transitionContext viewControllerForKey:ECTransitionContextTopViewControllerKey];
topViewController.view.userInteractionEnabled = NO;
if (_isInteractive) {
UIViewController *underViewController = [transitionContext viewControllerForKey:ECTransitionContextUnderLeftControllerKey];
CGRect underViewInitialFrame = [transitionContext initialFrameForViewController:underViewController];
CGRect underViewFinalFrame = [transitionContext finalFrameForViewController:underViewController];
UIView *containerView = [transitionContext containerView];
CGFloat finalLeftEdge = CGRectGetMinX([transitionContext finalFrameForViewController:topViewController]);
CGFloat initialLeftEdge = CGRectGetMinX([transitionContext initialFrameForViewController:topViewController]);
CGFloat fullWidth = fabs(finalLeftEdge - initialLeftEdge);
CGRect underViewFrame;
if (CGRectIsEmpty(underViewInitialFrame)) {
underViewFrame = underViewFinalFrame;
} else {
underViewFrame = underViewInitialFrame;
}
underViewController.view.frame = underViewFrame;
[containerView insertSubview:underViewController.view belowSubview:topViewController.view];
self.positiveLeftToRight = initialLeftEdge < finalLeftEdge;
self.fullWidth = fullWidth;
} else {
[self.defaultAnimationController animateTransition:transitionContext];
}
}
#pragma mark - UIPanGestureRecognizer action
- (void)handlePanGesture:(UIPanGestureRecognizer *)recognizer {
if ([self.animator isRunning]) return;
UIView *topView = self.slidingViewController.topViewController.view;
CGFloat translationX = [recognizer translationInView:self.slidingViewController.view].x;
CGFloat velocityX = [recognizer velocityInView:self.slidingViewController.view].x;
// Blur effect
[self blurControl];
switch (recognizer.state) {
case UIGestureRecognizerStateBegan: {
BOOL isMovingRight = velocityX > 0;
CALayer *presentationLayer = (CALayer *)topView.layer.presentationLayer;
self.initialTopViewFrame = presentationLayer.frame;
_isInteractive = YES;
if (self.slidingViewController.currentTopViewPosition == ECSlidingViewControllerTopViewPositionCentered && isMovingRight && self.slidingViewController.underLeftViewController) {
[self.slidingViewController anchorTopViewToRightAnimated:YES];
} else if (self.slidingViewController.currentTopViewPosition == ECSlidingViewControllerTopViewPositionCentered && !isMovingRight && self.slidingViewController.underRightViewController) {
[self.slidingViewController anchorTopViewToLeftAnimated:YES];
} else if (self.slidingViewController.currentTopViewPosition == ECSlidingViewControllerTopViewPositionAnchoredLeft) {
[self.slidingViewController resetTopViewAnimated:YES];
} else if (self.slidingViewController.currentTopViewPosition == ECSlidingViewControllerTopViewPositionAnchoredRight) {
[self.slidingViewController resetTopViewAnimated:YES];
} else {
_isInteractive = NO;
}
break;
}
case UIGestureRecognizerStateChanged: {
if (!_isInteractive) return;
CGRect topViewInitialFrame = self.initialTopViewFrame;
CGFloat newLeftEdge = topViewInitialFrame.origin.x + translationX;
if (newLeftEdge < 0) {
newLeftEdge = 0;
} else if (newLeftEdge > self.slidingViewController.anchorRightRevealAmount) {
newLeftEdge = self.slidingViewController.anchorRightRevealAmount;
}
topViewInitialFrame.origin.x = newLeftEdge;
topView.frame = topViewInitialFrame;
if (!self.positiveLeftToRight) translationX = translationX * -1.0;
CGFloat percentComplete = (translationX / self.fullWidth);
if (percentComplete < 0) percentComplete = 0;
if (percentComplete > 100) percentComplete = 100;
[self.transitionContext updateInteractiveTransition:percentComplete];
break;
}
case UIGestureRecognizerStateEnded:
{
[self blurControl];
};
case UIGestureRecognizerStateCancelled: {
if (!_isInteractive) return;
_isInteractive = NO;
self.isPanningRight = velocityX > 0;
if (self.isPanningRight) {
[self blurControl];
} else {
[self disableBlur];
}
self.gravityBehavior.gravityDirection = self.isPanningRight ? CGVectorMake(2, 0) : CGVectorMake(-2, 0);
self.pushBehavior.angle = 0; // velocity may be negative
self.pushBehavior.magnitude = velocityX;
self.pushBehavior.active = YES;
[self.animator addBehavior:self.compositeBehavior];
break;
}
default:
break;
}
}
#pragma mark - UIDynamicAnimatorDelegate
- (void)dynamicAnimatorDidPause:(UIDynamicAnimator*)animator {
[self.animator removeAllBehaviors];
_collisionBehavior = nil;
_topViewBehavior = nil;
_pushBehavior = nil;
_gravityBehavior = nil;
_compositeBehavior = nil;
_animator = nil;
self.slidingViewController.topViewController.view.userInteractionEnabled = YES;
UIViewController *topViewController = [self.transitionContext viewControllerForKey:ECTransitionContextTopViewControllerKey];
if ((self.isPanningRight && self.positiveLeftToRight) || (!self.isPanningRight && !self.positiveLeftToRight)) {
topViewController.view.frame = [self.transitionContext finalFrameForViewController:topViewController];
[self.transitionContext finishInteractiveTransition];
} else if ((self.isPanningRight && !self.positiveLeftToRight) || (!self.isPanningRight && self.positiveLeftToRight)) {
topViewController.view.frame = [self.transitionContext initialFrameForViewController:topViewController];
[self.transitionContext cancelInteractiveTransition];
}
[self.transitionContext completeTransition:YES];
}
#pragma mark - Blur
- (void) setBlurOffset:(CGFloat) offset {
UIView *topView = self.slidingViewController.topViewController.view;
if (!effectView) {
UIBlurEffect * blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark];
effectView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];
effectView.frame = topView.bounds;
effectView.alpha = 0.1f;
[topView addSubview:effectView];
[effectView setTranslatesAutoresizingMaskIntoConstraints:false];
[topView addConstraint:[NSLayoutConstraint constraintWithItem:effectView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:topView attribute:NSLayoutAttributeTop multiplier:1 constant:0]];
[topView addConstraint:[NSLayoutConstraint constraintWithItem:effectView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:topView attribute:NSLayoutAttributeBottom multiplier:1 constant:0]];
[topView addConstraint:[NSLayoutConstraint constraintWithItem:effectView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:topView attribute:NSLayoutAttributeLeading multiplier:1 constant:0]];
[topView addConstraint:[NSLayoutConstraint constraintWithItem:effectView attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:topView attribute:NSLayoutAttributeTrailing multiplier:1 constant:0]];
}
CGFloat c = offset / 100;
if (c < 0.1f) c = 0.1f; else if (c > 0.5f) c = 0.5f;
effectView.alpha = c;
}
- (void) disableBlur{
if (effectView != NULL) {
[effectView removeFromSuperview];
effectView = NULL;
}
}
- (void) blurControl{
UIView *topView = self.slidingViewController.topViewController.view;
NSLog(#"X: %f", topView.frame.origin.x);
if (topView.frame.origin.x >= 15) {
[self setBlurOffset:topView.frame.origin.x];
} else {
[self disableBlur];
}
}
#end
I have a view controller presenting another view controller with modalPresentationStyle = UIModalPresentationCustom. Things are set up so that part of the presenting view controller's view shows up underneath the presented view controller's view. In this state, the presenting view controller still handles auto-rotation correctly, and I handle rotation for the presented view controller using autolayout.
I'm now trying to implement interactively dismissing the presented view controller using iOS 7's custom view controller transitioning API. It works except that, when the interactive dismissal is canceled, handling of auto-rotation stops working. (It works again after the presented view controller is dismissed later.) Why is this happening, and how can I fix this?
EDIT: Here is code you can run to demonstrate the problem. A view pops up from below, and you can dismiss it by swiping it down. If you cancel dismissal by not swiping it all the way down, the presenting view controller's view no longer responds to rotations, and the presented view controller's view has messed-up layout.
EDIT: Here is the link to the code below as an Xcode project:
https://drive.google.com/file/d/0BwcBqUuDfCG2YlhVWE1QekhUWlk/edit?usp=sharing
Sorry for the massive code dump, but I don't know what I'm doing wrong. Here's a sketch of what is going on: ViewController1 presents ViewController2. ViewController1 implements UIViewControllerTransitioningDelegate, so it is returning the animation/interactive controllers for the transitions. ViewController2 has a pan gesture recognizer that drives the interactive dismissal; it implements UIViewControllerInteractiveTransitioning to serve as the interactive controller for dismissal. It also keeps a reference to the animation controller for dismissal to finish the transition if the user drags the view down far enough. Finally, there are two animation controller objects. PresentAnimationController sets up the autolayout constraints to handle rotations for the presented view controller's view, and DismissAnimationController finishes up the dismissal.
ViewController1.h
#import <UIKit/UIKit.h>
#interface ViewController1 : UIViewController <UIViewControllerTransitioningDelegate>
#end
ViewController1.m
#import "ViewController1.h"
#import "ViewController2.h"
#import "PresentAnimationController.h"
#import "DismissAnimationController.h"
#implementation ViewController1
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
self.title = #"View 1";
self.navigationItem.prompt = #"Press “Present” and then swipe down to dismiss.";
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:#"Present" style:UIBarButtonItemStylePlain target:self action:#selector(pressedPresentButton:)];
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
// Some subview just to check if layout is working.
UIView * someSubview = [[UIView alloc] initWithFrame:self.view.bounds];
someSubview.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
someSubview.backgroundColor = [UIColor orangeColor];
someSubview.layer.borderColor = [UIColor redColor].CGColor;
someSubview.layer.borderWidth = 2;
[self.view addSubview:someSubview];
}
// --------------------
- (void)pressedPresentButton:(id)sender
{
ViewController2 * presentedVC = [[ViewController2 alloc] initWithNibName:nil bundle:nil];
presentedVC.modalPresentationStyle = UIModalPresentationCustom;
presentedVC.transitioningDelegate = self;
[self presentViewController:presentedVC animated:YES completion:nil];
}
// --------------------
// View Controller Transitioning Delegate Methods.
- (id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source
{
return [[PresentAnimationController alloc] init];;
}
- (id <UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed
{
DismissAnimationController * animationController = [[DismissAnimationController alloc] init];
ViewController2 * presentedVC = (ViewController2 *)self.presentedViewController;
if (presentedVC.dismissalIsInteractive) {
presentedVC.dismissAnimationController = animationController;
}
return animationController;
}
- (id <UIViewControllerInteractiveTransitioning>)interactionControllerForPresentation:(id <UIViewControllerAnimatedTransitioning>)animator
{
return nil;
}
- (id <UIViewControllerInteractiveTransitioning>)interactionControllerForDismissal:(id <UIViewControllerAnimatedTransitioning>)animator
{
ViewController2 * presentedVC = (ViewController2 *)self.presentedViewController;
if (presentedVC.dismissalIsInteractive) {
return presentedVC;
}
else {
return nil;
}
}
#end
ViewController2.h
#import <UIKit/UIKit.h>
#import "DismissAnimationController.h"
#interface ViewController2 : UIViewController <UIViewControllerInteractiveTransitioning>
#property (weak, nonatomic) UIView * contentView;
#property (nonatomic, readonly) BOOL dismissalIsInteractive;
#property (strong, nonatomic) DismissAnimationController * dismissAnimationController;
#end
ViewController2.m
#import "ViewController2.h"
#interface ViewController2 ()
#property (strong, nonatomic) id<UIViewControllerContextTransitioning> transitionContext;
#end
#implementation ViewController2
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
_dismissalIsInteractive = NO;
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = [UIColor colorWithWhite:0 alpha:0.5];
// Set up content view.
CGRect frame = UIEdgeInsetsInsetRect(self.view.bounds, UIEdgeInsetsMake(15, 15, 15, 15));
UIView * contentView = [[UIView alloc] initWithFrame:frame];
self.contentView = contentView;
contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
contentView.backgroundColor = [UIColor cyanColor];
contentView.layer.borderColor = [UIColor blueColor].CGColor;
contentView.layer.borderWidth = 2;
[self.view addSubview:contentView];
// Set up pan dismissal gesture recognizer.
UIPanGestureRecognizer * panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(dismissalPan:)];
[self.view addGestureRecognizer:panGesture];
}
// --------------------
- (void)dismissalPan:(UIPanGestureRecognizer *)panGesture
{
switch (panGesture.state) {
case UIGestureRecognizerStateBegan: {
_dismissalIsInteractive = YES;
[self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
break;
}
case UIGestureRecognizerStateChanged: {
CGPoint translation = [panGesture translationInView:self.view];
CGFloat percent;
if (translation.y > 0) {
percent = translation.y / self.view.bounds.size.height;
percent = MIN(percent, 1.0);
}
else {
percent = 0;
}
// Swiping content view down.
CGPoint center;
center.x = CGRectGetMidX(self.view.bounds);
center.y = CGRectGetMidY(self.view.bounds);
if (translation.y > 0) {
center.y += translation.y; // Only allow swiping down.
}
self.contentView.center = center;
self.view.backgroundColor = [UIColor colorWithWhite:0 alpha:(0.5 * (1.0 - percent))];
[self.transitionContext updateInteractiveTransition:percent];
break;
}
case UIGestureRecognizerStateEnded: // Fall through.
case UIGestureRecognizerStateCancelled: {
_dismissalIsInteractive = NO;
id<UIViewControllerContextTransitioning> transitionContext = self.transitionContext;
self.transitionContext = nil;
DismissAnimationController * dismissAnimationController = self.dismissAnimationController;
self.dismissAnimationController = nil;
CGPoint translation = [panGesture translationInView:self.view];
if (translation.y > 100) {
// Complete dismissal.
[dismissAnimationController animateTransition:transitionContext];
}
else {
// Cancel dismissal.
void (^animations)() = ^() {
CGPoint center;
center.x = CGRectGetMidX(self.view.bounds);
center.y = CGRectGetMidY(self.view.bounds);
self.contentView.center = center;
self.view.backgroundColor = [UIColor colorWithWhite:0 alpha:0.5];
};
void (^completion)(BOOL) = ^(BOOL finished) {
[transitionContext cancelInteractiveTransition];
[transitionContext completeTransition:NO];
};
[UIView animateWithDuration:0.5 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:animations completion:completion];
}
break;
}
default: {
break;
}
}
}
// --------------------
// View Controller Interactive Transitioning Methods.
- (void)startInteractiveTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
self.transitionContext = transitionContext;
}
#end
PresentAnimationController.h
#import <Foundation/Foundation.h>
#interface PresentAnimationController : NSObject <UIViewControllerAnimatedTransitioning>
#end
PresentAnimationController.m
#import "PresentAnimationController.h"
#import "ViewController2.h"
#implementation PresentAnimationController
- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext
{
UIViewController * fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
ViewController2 * toVC = (ViewController2 *)[transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
UIView * containerView = [transitionContext containerView];
CGPoint toCenter = fromVC.view.center;
CGRect toBounds = fromVC.view.bounds;
toVC.view.center = toCenter;
toVC.view.bounds = toBounds;
[toVC.view layoutIfNeeded];
[containerView addSubview:fromVC.view];
[containerView addSubview:toVC.view];
CGRect contentViewEndFrame = toVC.contentView.frame;
CGRect contentViewStartFrame = contentViewEndFrame;
contentViewStartFrame.origin.y += contentViewStartFrame.size.height;
toVC.contentView.frame = contentViewStartFrame;
UIColor * endBackgroundColor = toVC.view.backgroundColor;
toVC.view.backgroundColor = [UIColor clearColor];
void (^animations)() = ^() {
toVC.contentView.frame = contentViewEndFrame;
toVC.view.backgroundColor = endBackgroundColor;
};
void (^completion)(BOOL) = ^(BOOL finished) {
toVC.view.autoresizingMask = UIViewAutoresizingNone;
toVC.view.translatesAutoresizingMaskIntoConstraints = NO;
NSLayoutConstraint * centerXConstraint = [NSLayoutConstraint constraintWithItem:toVC.view
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:fromVC.view
attribute:NSLayoutAttributeCenterX
multiplier:1
constant:0];
NSLayoutConstraint * centerYConstraint = [NSLayoutConstraint constraintWithItem:toVC.view
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:fromVC.view
attribute:NSLayoutAttributeCenterY
multiplier:1
constant:0];
NSLayoutConstraint * widthConstraint = [NSLayoutConstraint constraintWithItem:toVC.view
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:fromVC.view
attribute:NSLayoutAttributeWidth
multiplier:1
constant:0];
NSLayoutConstraint * heightConstraint = [NSLayoutConstraint constraintWithItem:toVC.view
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:fromVC.view
attribute:NSLayoutAttributeHeight
multiplier:1
constant:0];
[containerView addConstraint:centerXConstraint];
[containerView addConstraint:centerYConstraint];
[containerView addConstraint:widthConstraint];
[containerView addConstraint:heightConstraint];
[transitionContext completeTransition:YES];
};
[UIView animateWithDuration:0.5 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:animations completion:completion];
}
- (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext
{
return 0.5;
}
#end
DismissAnimationController.h
#import <Foundation/Foundation.h>
#interface DismissAnimationController : NSObject <UIViewControllerAnimatedTransitioning>
#end
DismissAnimationController.m
#import "DismissAnimationController.h"
#import "ViewController2.h"
#implementation DismissAnimationController
- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext
{
ViewController2 * fromVC = (ViewController2 *)[transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController * toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
UIView * containerView = [transitionContext containerView];
[containerView addSubview:toVC.view];
[containerView addSubview:fromVC.view];
void (^animations)() = ^() {
CGRect contentViewEndFrame = fromVC.contentView.frame;
contentViewEndFrame.origin.y = CGRectGetMaxY(fromVC.view.bounds) + 15;
fromVC.contentView.frame = contentViewEndFrame;
fromVC.view.backgroundColor = [UIColor clearColor];
};
void (^completion)(BOOL) = ^(BOOL finished) {
if ([transitionContext isInteractive]) {
[transitionContext finishInteractiveTransition];
}
[transitionContext completeTransition:YES];
};
[UIView animateWithDuration:0.5 delay:0 options:UIViewAnimationOptionCurveLinear animations:animations completion:completion];
}
- (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext
{
return 0.5;
}
#end
AppDelegate.m
#import "AppDelegate.h"
#import "ViewController1.h"
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
ViewController1 * vc = [[ViewController1 alloc] initWithNibName:nil bundle:nil];
UINavigationController * nav = [[UINavigationController alloc] initWithRootViewController:vc];
self.window.rootViewController = nav;
[self.window makeKeyAndVisible];
return YES;
}
#end
I think I found your problem. in your PresentAnimationController.m you specify toVC.view.translatesAutoresizingMaskIntoConstraints = NO; and you set all of your constraints in the completion block you set in
- (void)animateTransition:
Comment that line out and all of the constraints and addConstraint: calls and it should work
EDIT:
Just saw it worked only when the gesture was cancelled and not when the view is initially displayed. Comment out everything in the completion block except for
[transitionContext completeTransition:YES];
I'm new to ios and also core animation so I'm doing some tests to get used to it.
I've got a menu I'm trying to create by doing a long press gesture. I want the button to by animating up and then animate down and then disappear. I got the appearing part working, but I can't figure out how to make it disappear. It also doesn't let me animate my imageView in my UIGestureRecognizerStateEnded statement. Basically, I have two questions:
How can I animate the button going down when the long press is released?
How can I only make one of these buttons instead of them appearing every time I do a long press?
Here's what I have in my .m
-(void)onPress:(UILongPressGestureRecognizer*)longpress{
CGPoint touchCenter = [longpress locationInView:self.view];
UIImage *plus = [UIImage imageNamed:#"plus"];
imageView = [[UIImageView alloc]initWithImage:plus];
CGRect imageViewFrame = CGRectMake(0, 0, 35, 35);
imageViewFrame.origin = CGPointMake(touchCenter.x - imageViewFrame.size.width / 2.0f, touchCenter.y - imageViewFrame.size.height / 2.0f);
imageView.frame = imageViewFrame;
if (longpress.state == UIGestureRecognizerStateBegan) {
[self.view addSubview:imageView];
[UIView animateWithDuration:0.6 animations:^{
CGAffineTransform moveTrans = CGAffineTransformMakeTranslation(0, -40);
imageView.transform = moveTrans;
}];
NSLog(#"Long press");
return;
}else{
if (longpress.state == UIGestureRecognizerStateEnded || longpress.state == UIGestureRecognizerStateCancelled || longpress.state == UIGestureRecognizerStateFailed) {
[UIView animateWithDuration:0.6 animations:^{
CGAffineTransform moveTrans = CGAffineTransformMakeTranslation(0, 40);
imageView.transform = moveTrans;
NSLog(#"long press done");
}];
}
}
}
and my .h
#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>
#interface ViewController : UIViewController<UIGestureRecognizerDelegate>
{
UIImageView *imageView;
CAShapeLayer *layer;
}
#property(nonatomic) float angle;
#property(nonatomic, strong) UIImageView *imageView;
#property (nonatomic, strong) UIImage *image;
#end
I'm now sure what you want to do. But I modified some of your code:
#interface ViewController ()
#property (strong, nonatomic) UIView *moveView;
#end
- (void)viewDidLoad
{
[super viewDidLoad];
UILongPressGestureRecognizer *recoginzer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(onPress:)];
[self.view addGestureRecognizer:recoginzer];
}
- (void)onPress:(UILongPressGestureRecognizer*)longpress {
CGPoint location = [longpress locationInView:self.view];
if (longpress.state == UIGestureRecognizerStateBegan) {
if (!self.moveView) {
self.moveView = [[UIView alloc] initWithFrame:CGRectMake(location.x, location.y, 100, 100)];
self.moveView.backgroundColor = [UIColor redColor];
[self.view addSubview:self.moveView];
} else {
self.moveView.frame = CGRectMake(location.x, location.y, 100, 100);
}
[UIView animateWithDuration:0.6 animations:^{
CGAffineTransform moveTrans = CGAffineTransformMakeTranslation(0, -40);
self.moveView.transform = moveTrans;
}];
NSLog(#"Long press");
} else if (longpress.state == UIGestureRecognizerStateEnded || longpress.state == UIGestureRecognizerStateCancelled || longpress.state == UIGestureRecognizerStateFailed) {
[UIView animateWithDuration:0.6 animations:^{
CGAffineTransform moveTrans = CGAffineTransformMakeTranslation(0, 40);
self.moveView.transform = moveTrans;
NSLog(#"long press done");
}];
}
}
Let me know if you need more help.
I have created a SlidingViewController which has a Main, Right, and Left view controllers. Now I want to add a new function/method that is called whenever one of the RightViewController's table view cell is clicked to switch the main view controller to what ever view controller is linked with that table view cell at indexpath.row. The new view controller should still be able to have this right and left view controller available. Anyone have any experience creating their own SlidingViewController or MenuViewController that can help out on how I should approach this? Any help will be gratefully appreciated. Thank you in advance.
SlidingViewController.h
#interface SlidingViewController : UIViewController <UIGestureRecognizerDelegate>
#property (retain) UIViewController *mainViewController;
#property (retain) UIViewController *leftViewController;
#property (retain) UIViewController *rightViewController;
#property (retain) NSNumber *leftSwipeEnabled;
#property (assign) BOOL leftDrawerVisible;
#property (retain) NSNumber *rightSwipeEnabled;
#property (assign) BOOL rightDrawerVisible;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil mainViewController:(UIViewController *)main leftViewController:(UIViewController *)left andRightViewController:(UIViewController *)right;
-(void)toggleLeftDrawer;
-(void)toggleRightDrawer;
#end
SlidingViewController.m
#implementation SlidingViewController
#synthesize mainViewController, leftViewController, rightViewController;
#synthesize leftDrawerVisible, rightDrawerVisible;
#synthesize leftSwipeEnabled, rightSwipeEnabled;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil mainViewController:(UIViewController *)main leftViewController:(UIViewController *)left andRightViewController:(UIViewController *)right
{
if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])
{
mainViewController = main;
leftViewController = left;
rightViewController = right;
leftSwipeEnabled = [NSNumber numberWithBool:NO];
rightSwipeEnabled = [NSNumber numberWithBool:NO];
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self addChildViewController:self.mainViewController];
[self.view addSubview:[self.mainViewController view]];
self.mainViewController.view.frame = self.view.frame;
[self.mainViewController didMoveToParentViewController:self];
self.mainViewController.view.layer.shadowColor = [UIColor blackColor].CGColor;
self.mainViewController.view.layer.shadowOpacity = 0.2f;
self.mainViewController.view.layer.shadowRadius = 5.0f;
CGPathRef path = [UIBezierPath bezierPathWithRect:self.mainViewController.view.bounds].CGPath;
self.mainViewController.view.layer.shadowPath = path;
if(self.leftViewController != nil)
{
UISwipeGestureRecognizer *leftSwipeRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(handleSwipe:)];
leftSwipeRecognizer.direction = UISwipeGestureRecognizerDirectionRight;
leftSwipeRecognizer.delegate = self;
[self.mainViewController.view addGestureRecognizer:leftSwipeRecognizer];
}
if(self.rightViewController != nil)
{
UISwipeGestureRecognizer *rightSwipeRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(handleSwipe:)];
rightSwipeRecognizer.direction = UISwipeGestureRecognizerDirectionLeft;
rightSwipeRecognizer.delegate = self;
[self.mainViewController.view addGestureRecognizer:rightSwipeRecognizer];
}
}
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self layoutShadowWithDuration:0];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesBegan:touches withEvent:event];
if(self.leftDrawerVisible)
[self toggleLeftDrawer];
else if(self.rightDrawerVisible)
[self toggleRightDrawer];
}
-(BOOL) gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
}
-(void)handleSwipe:(UISwipeGestureRecognizer *)recognizer
{
if(recognizer.state == UIGestureRecognizerStateEnded)
{
if(recognizer.direction == UISwipeGestureRecognizerDirectionRight && [self.leftSwipeEnabled boolValue])
[self toggleLeftDrawer];
else if(recognizer.direction == UISwipeGestureRecognizerDirectionLeft && [self.rightSwipeEnabled boolValue])
[self toggleRightDrawer];
}
}
-(void)toggleLeftDrawer
{
if (self.rightDrawerVisible)
{
return;
}
if(self.leftDrawerVisible)
{
[UIView animateWithDuration:0.2
delay:0.0
options:UIViewAnimationOptionCurveLinear
animations:^{
self.mainViewController.view.frame = CGRectMake(0.0, 0.0, self.mainViewController.view.frame.size.width, self.mainViewController.view.frame.size.height);}
completion:^(BOOL finished)
{
[self.leftViewController.view removeFromSuperview];
[self.leftViewController willMoveToParentViewController:nil];
[self.leftViewController removeFromParentViewController];
}];
self.leftDrawerVisible = NO;
self.mainViewController.view.userInteractionEnabled = YES;
}
else
{
[self addChildViewController:self.leftViewController];
[self.view insertSubview:[self.leftViewController view] belowSubview:[self.mainViewController view]];
[self.leftViewController didMoveToParentViewController:self];
CGPathRef path = [UIBezierPath bezierPathWithRect:self.mainViewController.view.bounds].CGPath;
self.mainViewController.view.layer.shadowPath = path;
self.mainViewController.view.layer.shadowOffset = CGSizeMake(-3, 0);
NSInteger width = 260;
if([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad)
width = 320;
self.leftViewController.view.frame = CGRectMake(0, 0, width, self.view.bounds.size.height);
[UIView animateWithDuration:0.2
delay:0.0
options:UIViewAnimationOptionCurveLinear
animations:^{ self.mainViewController.view.frame = CGRectMake(width, 0, self.mainViewController.view.frame.size.width, self.mainViewController.view.frame.size.height); }
completion:^(BOOL finished) { self.leftViewController.view.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleLeftMargin; }];
self.leftDrawerVisible = YES;
self.mainViewController.view.userInteractionEnabled = NO;
}
}
-(void)toggleRightDrawer
{
if(self.leftDrawerVisible)
return;
if(self.rightDrawerVisible)
{
[UIView animateWithDuration:0.2
delay:0.0
options:UIViewAnimationOptionCurveLinear
animations:^{
self.mainViewController.view.frame = CGRectMake(0.0, 0.0, self.mainViewController.view.frame.size.width, self.mainViewController.view.frame.size.height);
}
completion:^(BOOL finished){
[self.rightViewController.view removeFromSuperview];
[self.rightViewController willMoveToParentViewController:nil];
[self.rightViewController removeFromParentViewController];
}];
self.rightDrawerVisible = NO;
self.mainViewController.view.userInteractionEnabled = YES;
}
else
{
[self addChildViewController:self.rightViewController];
[self.view insertSubview:[self.rightViewController view] belowSubview:[self.mainViewController view]];
[self.rightViewController didMoveToParentViewController:self];
CGPathRef path = [UIBezierPath bezierPathWithRect:self.mainViewController.view.bounds].CGPath;
self.mainViewController.view.layer.shadowPath = path;
self.mainViewController.view.layer.shadowOffset = CGSizeMake(3, 0);
NSInteger width = 260;
if([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad)
width = 320;
self.rightViewController.view.frame = CGRectMake(self.view.bounds.size.width- width, 0, width, self.view.bounds.size.height);
[UIView animateWithDuration:0.2 delay:0.0
options:UIViewAnimationOptionCurveLinear
animations:^{
self.mainViewController.view.frame = CGRectMake(-width, 0, self.mainViewController.view.frame.size.width, self.mainViewController.view.frame.size.height);
}
completion:^(BOOL finished){
self.rightViewController.view.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleLeftMargin;
}];
self.rightDrawerVisible = YES;
self.mainViewController.view.userInteractionEnabled = NO;
}
}
-(void) layoutShadowWithDuration:(NSTimeInterval)duration
{
CGPathRef oldShadowPath = self.mainViewController.view.layer.shadowPath;
if (oldShadowPath)
{
CFRetain(oldShadowPath);
}
// Update shadow path for the view
CGPathRef path = [UIBezierPath bezierPathWithRect:self.mainViewController.view.bounds].CGPath;
self.mainViewController.view.layer.shadowPath = path;
// You would think setting duration to 0 would cause the animation added below to not animate. You would be wrong.
if (duration != 0)
{
if (oldShadowPath)
{
[self.mainViewController.view.layer addAnimation:((^ {
CABasicAnimation *transition = [CABasicAnimation animationWithKeyPath:#"shadowPath"];
transition.fromValue = (__bridge id)oldShadowPath;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
transition.duration = duration;
return transition;
})()) forKey:#"transition"];
CFRelease(oldShadowPath);
}
else
if (oldShadowPath)
CFRelease(oldShadowPath);
}
else
if (oldShadowPath)
CFRelease(oldShadowPath);
}
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
[self layoutShadowWithDuration:duration];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#end
You can simply do this by "Delegation Design Pattern"
In RightViewController.h add the following lines.
#protocol RightViewControllerDelegate <NSObject>
#required
- (void)somethingClicked : (id)theObject;
#end
#interface RightViewController : UIViewController
#property (nonatomic, assign) id<RightViewControllerDelegate> delegate;
#end
In RightViewController.m add the following lines.
- (void)somethingClicked : (id)theObject
{
[_delegate somethingClicked:theObject];
}
Update MainViewController.h with the following code.
#interface MainViewController : UIViewController <RightViewControllerDelegate>
And Finally add the following code in the MainViewController.m
- (void)somethingClicked : (id)theObject
{
// Perform Your Task
}