ECSlidingViewController:显示左侧菜单时模糊视图控制器
ECSlidingViewController: blur view controller when displaying left menu
我在我的应用程序中使用 ECSlidingViewController 来显示左侧菜单。
有什么方法可以让主视图控制器 'darker' 移动并显示左侧菜单时?
谢谢。
我解决了这个问题。
只需从示例中获取一些 类 并更改它:
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
我在我的应用程序中使用 ECSlidingViewController 来显示左侧菜单。
有什么方法可以让主视图控制器 'darker' 移动并显示左侧菜单时?
谢谢。
我解决了这个问题。 只需从示例中获取一些 类 并更改它:
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