Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Many improvements #79

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions ZFDragableModalTransition/ZFModalTransitionAnimator.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,15 @@ typedef NS_ENUM(NSUInteger, ZFModalTransitonDirection) {
@property (nonatomic, weak) UIScrollView *scrollview;
@end

@class ZFModalTransitionAnimator;

@protocol ZFModalTransitionAnimatorDelegate
- (BOOL)modalTransitionAnimatorShouldBegin:(ZFModalTransitionAnimator *)animator;
@end

@interface ZFModalTransitionAnimator : UIPercentDrivenInteractiveTransition <UIViewControllerAnimatedTransitioning, UIViewControllerTransitioningDelegate, UIGestureRecognizerDelegate>

@property (nonatomic, weak) id<ZFModalTransitionAnimatorDelegate> delegate;
@property (nonatomic, assign, getter=isDragable) BOOL dragable;
@property (nonatomic, readonly) ZFDetectScrollViewEndGestureRecognizer *gesture;
@property (nonatomic, assign) UIGestureRecognizer *gestureRecognizerToFailPan;
Expand All @@ -29,6 +36,8 @@ typedef NS_ENUM(NSUInteger, ZFModalTransitonDirection) {
@property CGFloat behindViewScale;
@property CGFloat behindViewAlpha;
@property CGFloat transitionDuration;
@property CGFloat dismissVelocity;
@property CGFloat dismissDistance;

- (id)initWithModalViewController:(UIViewController *)modalViewController;
- (void)setContentScrollView:(UIScrollView *)scrollView;
Expand Down
248 changes: 156 additions & 92 deletions ZFDragableModalTransition/ZFModalTransitionAnimator.m
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ @interface ZFModalTransitionAnimator ()
@property (nonatomic, strong) ZFDetectScrollViewEndGestureRecognizer *gesture;
@property (nonatomic, strong) id<UIViewControllerContextTransitioning> transitionContext;
@property CGFloat panLocationStart;
@property CGFloat scrollViewOffsetStart;
@property BOOL isDismiss;
@property BOOL isInteractive;
@property CATransform3D tempTransform;
Expand All @@ -30,6 +31,8 @@ - (instancetype)initWithModalViewController:(UIViewController *)modalViewControl
_behindViewScale = 0.9f;
_behindViewAlpha = 1.0f;
_transitionDuration = 0.8f;
_dismissVelocity = 100.0f;
_dismissDistance = 100.0f;

[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self
Expand Down Expand Up @@ -133,25 +136,37 @@ - (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionCo
if (toViewController.modalPresentationStyle == UIModalPresentationCustom) {
[fromViewController beginAppearanceTransition:NO animated:YES];
}

[UIView animateWithDuration:[self transitionDuration:transitionContext]
delay:0
usingSpringWithDamping:0.8
initialSpringVelocity:0.1
options:UIViewAnimationOptionCurveEaseOut
animations:^{
fromViewController.view.transform = CGAffineTransformScale(fromViewController.view.transform, self.behindViewScale, self.behindViewScale);
fromViewController.view.alpha = self.behindViewAlpha;

toViewController.view.frame = CGRectMake(0,0,
CGRectGetWidth(toViewController.view.frame),
CGRectGetHeight(toViewController.view.frame));
} completion:^(BOOL finished) {
if (toViewController.modalPresentationStyle == UIModalPresentationCustom) {
[fromViewController endAppearanceTransition];
}
[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
}];

void (^animations)() = ^{
fromViewController.view.transform = CGAffineTransformScale(fromViewController.view.transform, self.behindViewScale, self.behindViewScale);
fromViewController.view.alpha = self.behindViewAlpha;

toViewController.view.frame = CGRectMake(0,0,
CGRectGetWidth(toViewController.view.frame),
CGRectGetHeight(toViewController.view.frame));
};
void (^completion)(BOOL) = ^(BOOL finished){
if (toViewController.modalPresentationStyle == UIModalPresentationCustom) {
[fromViewController endAppearanceTransition];
}
[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
};

if(self.bounces){
[UIView animateWithDuration:[self transitionDuration:transitionContext]
delay:0
usingSpringWithDamping:0.8
initialSpringVelocity:0.1
options:UIViewAnimationOptionCurveEaseOut
animations:animations
completion:completion];
} else {
[UIView animateWithDuration:[self transitionDuration:transitionContext]
delay:0.0
options:UIViewAnimationOptionCurveEaseOut
animations:animations
completion:completion];
}
} else {

if (fromViewController.modalPresentationStyle == UIModalPresentationFullScreen) {
Expand Down Expand Up @@ -192,23 +207,35 @@ - (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionCo
[toViewController beginAppearanceTransition:YES animated:YES];
}

[UIView animateWithDuration:[self transitionDuration:transitionContext]
delay:0
usingSpringWithDamping:0.8
initialSpringVelocity:0.1
options:UIViewAnimationOptionCurveEaseOut
animations:^{
CGFloat scaleBack = (1 / self.behindViewScale);
toViewController.view.layer.transform = CATransform3DScale(toViewController.view.layer.transform, scaleBack, scaleBack, 1);
toViewController.view.alpha = 1.0f;
fromViewController.view.frame = endRect;
} completion:^(BOOL finished) {
toViewController.view.layer.transform = CATransform3DIdentity;
if (fromViewController.modalPresentationStyle == UIModalPresentationCustom) {
[toViewController endAppearanceTransition];
}
[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
}];
void (^animations)() = ^{
CGFloat scaleBack = (1 / self.behindViewScale);
toViewController.view.layer.transform = CATransform3DScale(toViewController.view.layer.transform, scaleBack, scaleBack, 1);
toViewController.view.alpha = 1.0f;
fromViewController.view.frame = endRect;
};
void (^completion)(BOOL) = ^(BOOL finished){
toViewController.view.layer.transform = CATransform3DIdentity;
if (fromViewController.modalPresentationStyle == UIModalPresentationCustom) {
[toViewController endAppearanceTransition];
}
[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
};

if(self.bounces){
[UIView animateWithDuration:[self transitionDuration:transitionContext]
delay:0
usingSpringWithDamping:0.8
initialSpringVelocity:0.1
options:UIViewAnimationOptionCurveEaseOut
animations:animations
completion:completion];
} else {
[UIView animateWithDuration:[self transitionDuration:transitionContext]
delay:0.0
options:UIViewAnimationOptionCurveEaseOut
animations:animations
completion:completion];
}
}
}

Expand All @@ -235,6 +262,7 @@ - (void)handlePan:(UIPanGestureRecognizer *)recognizer
self.isInteractive = YES;
if (self.direction == ZFModalTransitonDirectionBottom) {
self.panLocationStart = location.y;
self.scrollViewOffsetStart = self.gesture.scrollview.contentOffset.y;
} else {
self.panLocationStart = location.x;
}
Expand All @@ -244,7 +272,13 @@ - (void)handlePan:(UIPanGestureRecognizer *)recognizer
CGFloat animationRatio = 0;

if (self.direction == ZFModalTransitonDirectionBottom) {
animationRatio = (location.y - self.panLocationStart) / (CGRectGetHeight([self.modalController view].bounds));
CGFloat yOffset = location.y - self.panLocationStart;
BOOL isMovingDown = yOffset > 0;
if (isMovingDown) {
animationRatio = (yOffset) / (CGRectGetHeight([self.modalController view].bounds));
} else {
self.gesture.scrollview.contentOffset = CGPointMake(self.gesture.scrollview.contentOffset.x, self.scrollViewOffsetStart - yOffset);
}
} else if (self.direction == ZFModalTransitonDirectionLeft) {
animationRatio = (self.panLocationStart - location.x) / (CGRectGetWidth([self.modalController view].bounds));
} else if (self.direction == ZFModalTransitonDirectionRight) {
Expand All @@ -254,24 +288,26 @@ - (void)handlePan:(UIPanGestureRecognizer *)recognizer
[self updateInteractiveTransition:animationRatio];

} else if (recognizer.state == UIGestureRecognizerStateEnded) {

CGFloat velocityForSelectedDirection;

CGFloat distanceOnSelectedDirection;
if (self.direction == ZFModalTransitonDirectionBottom) {
velocityForSelectedDirection = velocity.y;
distanceOnSelectedDirection = location.y - self.panLocationStart;
} else {
velocityForSelectedDirection = velocity.x;
if (self.direction == ZFModalTransitonDirectionLeft) {
velocityForSelectedDirection = -velocity.x;
distanceOnSelectedDirection = self.panLocationStart - location.x;
} else if (self.direction == ZFModalTransitonDirectionRight) {
velocityForSelectedDirection = velocity.x;
distanceOnSelectedDirection = location.x - self.panLocationStart;
}
}

if (velocityForSelectedDirection > 100
&& (self.direction == ZFModalTransitonDirectionRight
|| self.direction == ZFModalTransitonDirectionBottom)) {
[self finishInteractiveTransition];
} else if (velocityForSelectedDirection < -100 && self.direction == ZFModalTransitonDirectionLeft) {
[self finishInteractiveTransition];
} else {
[self cancelInteractiveTransition];
}
if (velocityForSelectedDirection > _dismissVelocity || distanceOnSelectedDirection > _dismissDistance) {
[self finishInteractiveTransition];
} else {
[self cancelInteractiveTransition];
}
self.isInteractive = NO;
}
}
Expand Down Expand Up @@ -381,50 +417,73 @@ - (void)finishInteractiveTransition
[toViewController beginAppearanceTransition:YES animated:YES];
}

[UIView animateWithDuration:[self transitionDuration:transitionContext]
delay:0
usingSpringWithDamping:0.8
initialSpringVelocity:0.1
options:UIViewAnimationOptionCurveEaseOut
animations:^{
CGFloat scaleBack = (1 / self.behindViewScale);
toViewController.view.layer.transform = CATransform3DScale(self.tempTransform, scaleBack, scaleBack, 1);
toViewController.view.alpha = 1.0f;
fromViewController.view.frame = endRect;
} completion:^(BOOL finished) {
if (fromViewController.modalPresentationStyle == UIModalPresentationCustom) {
[toViewController endAppearanceTransition];
}
[transitionContext completeTransition:YES];
}];
void (^animations)() = ^{
CGFloat scaleBack = (1 / self.behindViewScale);
toViewController.view.layer.transform = CATransform3DScale(self.tempTransform, scaleBack, scaleBack, 1);
fromViewController.view.alpha = 1.0f;
fromViewController.view.frame = endRect;
};
void (^completion)(BOOL) = ^(BOOL finished){
if (toViewController.modalPresentationStyle == UIModalPresentationCustom) {
[fromViewController endAppearanceTransition];
}
[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
};

if(self.bounces){
[UIView animateWithDuration:[self transitionDuration:transitionContext]
delay:0
usingSpringWithDamping:0.8
initialSpringVelocity:0.1
options:UIViewAnimationOptionCurveEaseOut
animations:animations
completion:completion];
} else {
[UIView animateWithDuration:[self transitionDuration:transitionContext]
delay:0.0
options:UIViewAnimationOptionCurveEaseOut
animations:animations
completion:completion];
}
}

- (void)cancelInteractiveTransition
{
id<UIViewControllerContextTransitioning> transitionContext = self.transitionContext;
[transitionContext cancelInteractiveTransition];


UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];

[UIView animateWithDuration:0.4
delay:0
usingSpringWithDamping:0.8
initialSpringVelocity:0.1
options:UIViewAnimationOptionCurveEaseOut
animations:^{
toViewController.view.layer.transform = self.tempTransform;
toViewController.view.alpha = self.behindViewAlpha;

fromViewController.view.frame = CGRectMake(0,0,
CGRectGetWidth(fromViewController.view.frame),
CGRectGetHeight(fromViewController.view.frame));
} completion:^(BOOL finished) {
[transitionContext completeTransition:NO];
if (fromViewController.modalPresentationStyle == UIModalPresentationFullScreen) {
[toViewController.view removeFromSuperview];
}
}];
void (^animations)() = ^{
toViewController.view.layer.transform = self.tempTransform;
toViewController.view.alpha = self.behindViewAlpha;

fromViewController.view.frame = CGRectMake(0,0,
CGRectGetWidth(fromViewController.view.frame),
CGRectGetHeight(fromViewController.view.frame));
};
void (^completion)(BOOL) = ^(BOOL finished){
[transitionContext completeTransition:NO];
if (fromViewController.modalPresentationStyle == UIModalPresentationFullScreen) {
[toViewController.view removeFromSuperview];
}
};

if(self.bounces){
[UIView animateWithDuration:[self transitionDuration:transitionContext]
delay:0
usingSpringWithDamping:0.8
initialSpringVelocity:0.1
options:UIViewAnimationOptionCurveEaseOut
animations:animations
completion:completion];
} else {
[UIView animateWithDuration:[self transitionDuration:transitionContext]
delay:0.0
options:UIViewAnimationOptionCurveEaseOut
animations:animations
completion:completion];
}
}

#pragma mark - UIViewControllerTransitioningDelegate Methods
Expand Down Expand Up @@ -459,6 +518,14 @@ - (void)cancelInteractiveTransition

#pragma mark - Gesture Delegate

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
if (self.delegate) {
return [self.delegate modalTransitionAnimatorShouldBegin:self];
}
return YES;
}

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
if (self.direction == ZFModalTransitonDirectionBottom) {
Expand Down Expand Up @@ -528,7 +595,9 @@ - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
return;
}

if (self.state == UIGestureRecognizerStateFailed) return;
if (self.state == UIGestureRecognizerStateFailed) {
return;
}
CGPoint velocity = [self velocityInView:self.view];
CGPoint nowPoint = [touches.anyObject locationInView:self.view];
CGPoint prevPoint = [touches.anyObject previousLocationInView:self.view];
Expand All @@ -540,13 +609,8 @@ - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
return;
}

CGFloat topVerticalOffset = -self.scrollview.contentInset.top;

if ((fabs(velocity.x) < fabs(velocity.y)) && (nowPoint.y > prevPoint.y) && (self.scrollview.contentOffset.y <= topVerticalOffset)) {
if ((fabs(velocity.x) < fabs(velocity.y)) && (nowPoint.y > prevPoint.y)) {
self.isFail = @NO;
} else if (self.scrollview.contentOffset.y >= topVerticalOffset) {
self.state = UIGestureRecognizerStateFailed;
self.isFail = @YES;
} else {
self.isFail = @NO;
}
Expand Down