1. 说明
由于iPhone X的面世,越来越多app依赖手势控制页面跳转。一般的转场动画只能指定一个方向,不能在同一个VC中,有2种不同的转场动画。本文仿照快闪app,snapchat app等视频app,视频页面在中间,可以左右滑动或者上下拖动,拖出相关的View。本文转场相关的知识参考:iOS自定义转场动画,在这边文章的基础下添加对同一个页面的不同手势的转场。
2.核心实现
添加一个左滑的LeftTransition处理左滑动画,添加一个右滑的RightTransition处理右滑动画,LeftViewController与RightViewController添加相应的代理,主要在ViewController这个中间VC中处理相应的操作。
ViewController文件中:
// 由于每次返回ViewController,都要初始化一次自定义转场动画方法,因为初始化函数放在viewDidAppear中
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self p_initInteractiveTransitionPush];
}
- (void)p_initInteractiveTransitionPush
{
self.interactiveTransitionPush = [[HYInteractiveTransiton alloc] init];
__weak typeof (self) weakSelf = self;
self.interactiveTransitionPush.pushConifg = ^(HYInteractiveTransitionGestureDirection direction){
__strong typeof (weakSelf) strongSelf = weakSelf;
// 根据滑动的方向来加载不同的VC
if(direction == HYInteractiveTransitionGestureDirectionRight)
{
[strongSelf leftPush];
}
else if(direction == HYInteractiveTransitionGestureDirectionLeft)
{
[strongSelf rightPush];
}
};
// 添加下拉手势的view
[self.interactiveTransitionPush addPanGestureForViewController:self];
}
- (void)rightPush
{
RightViewController *rightViewController = [[RightViewController alloc] init];
self.navigationController.delegate = rightViewController;
rightViewController.delegate = self;
[self.navigationController pushViewController:rightViewController animated:YES];
}
- (void)leftPush
{
LeftViewController *leftViewController = [[LeftViewController alloc] init];
self.navigationController.delegate = leftViewController;
leftViewController.delegate = self;
[self.navigationController pushViewController:leftViewController animated:YES];
}
#pragma mark -- PushControllerDelegate
- (id)interactiveTransitionForPush
{
return self.interactiveTransitionPush;
}
HYInteractiveTransition文件中
/*
* 手势过渡的过程
*/
- (void)handleGesture:(UIPanGestureRecognizer *)panGesture
{
//手势百分比
CGFloat persent = 0;
self.directionOut = HYInteractiveTransitionGestureDirctionNone;
// 这里判断在手势指定时是什么手势
if([panGesture translationInView:panGesture.view].x < 0)
{
if(-[panGesture translationInView:panGesture.view].x > ([panGesture translationInView:panGesture.view].y > 0 ? [panGesture translationInView:panGesture.view].y : -[panGesture translationInView:panGesture.view].y) )
{
self.directionOut = HYInteractiveTransitionGestureDirectionLeft;
}
}
else if([panGesture translationInView:panGesture.view].x > 0)
{
if([panGesture translationInView:panGesture.view].x > ([panGesture translationInView:panGesture.view].y > 0 ? [panGesture translationInView:panGesture.view].y : -[panGesture translationInView:panGesture.view].y) )
{
self.directionOut = HYInteractiveTransitionGestureDirectionRight;
}
}
// 已经指定了手势方向,判断手势滑动的百分比
switch (_direction)
{
case HYInteractiveTransitionGestureDirctionNone:
break;
case HYInteractiveTransitionGestureDirectionLeft:
{
CGFloat transitionX = -[panGesture translationInView:panGesture.view].x;
persent = transitionX / panGesture.view.frame.size.width;
}
break;
case HYInteractiveTransitionGestureDirectionRight:
{
CGFloat transitionX = [panGesture translationInView:panGesture.view].x;
persent = transitionX / panGesture.view.frame.size.width;
}
break;
case HYInteractiveTransitionGestureDirectionUp:
{
CGFloat transitionY = -[panGesture translationInView:panGesture.view].y;
persent = transitionY / panGesture.view.frame.size.width;
}
break;
case HYInteractiveTransitionGestureDirectionDown:
{
CGFloat transitionY = [panGesture translationInView:panGesture.view].y;
persent = transitionY / panGesture.view.frame.size.width;
}
break;
}
switch (panGesture.state)
{
case UIGestureRecognizerStateBegan:
{
//手势开始的时候标记手势状态,并开始相应的事件
self.interation = YES;
[self startGesture];
// 这里添加测试代码
// 首次触摸进入
self.isBeginSlid = YES;
self.originY = [panGesture translationInView:panGesture.view].y;
self.originDirection = HYInteractiveTransitionGestureDirctionNone;
if([panGesture translationInView:panGesture.view].x < 0)
{
if(-[panGesture translationInView:panGesture.view].x > ([panGesture translationInView:panGesture.view].y > 0 ? [panGesture translationInView:panGesture.view].y : -[panGesture translationInView:panGesture.view].y) )
{
self.originDirection = HYInteractiveTransitionGestureDirectionLeft;
}
}
else if([panGesture translationInView:panGesture.view].x > 0)
{
if([panGesture translationInView:panGesture.view].x > ([panGesture translationInView:panGesture.view].y > 0 ? [panGesture translationInView:panGesture.view].y : -[panGesture translationInView:panGesture.view].y) )
{
self.originDirection = HYInteractiveTransitionGestureDirectionRight;
}
}
}
break;
case UIGestureRecognizerStateChanged:
{
//手势过程中,通过updateInteractiveTransition设置pop过程进行的百分比
if(_direction != HYInteractiveTransitionGestureDirctionNone)
{
}
else if(!self.isFirst && self.bottomView.isHiddenView)
{
_type = HYInteractiveTransitionTypePush;
_direction = self.directionOut;
[self startGesture:self.directionOut];
self.isFirst = YES;
}
[self updateInteractiveTransition:persent];
// 不是左右滑动的话,采用以下方法判断是上下滑动加载view
if(!self.bottomView)
{
return;
}
if(self.bottomView.isHiddenView)
{
// 获取偏移位置
CGPoint tempCenter;
// 首次触摸进入
if(self.isBeginSlid)
{
if(self.originDirection != HYInteractiveTransitionGestureDirctionNone)
{
return;
}
// 判断是左右滑动还是上下滑动
if(ABS([panGesture translationInView:panGesture.view].x) > ABS([panGesture translationInView:panGesture.view].y))
{
}
else
{
tempCenter = self.bottomView.center;
tempCenter.y += ([panGesture translationInView:panGesture.view].y - self.originY);//上下滑动
self.originY = [panGesture translationInView:panGesture.view].y;
// 禁止向下划
if (self.bottomView.frame.origin.y == 0 && [panGesture translationInView:panGesture.view].y > 0)
{
//滑动开始是从0点开始的,并且是向下滑动
self.bottomView.center = tempCenter;
}
}
}
// 滑动开始后进入,滑动方向要么水平要么垂直
else
{
if (self.bottomView.frame.origin.y != 0)
{
tempCenter = self.bottomView.center;
tempCenter.y += ([panGesture translationInView:panGesture.view].y - self.originY);//上下滑动
self.originY = [panGesture translationInView:panGesture.view].y;
//禁止向下划
if (self.bottomView.frame.origin.y == 0 && [panGesture translationInView:panGesture.view].y > 0)
{
//滑动开始是从0点开始的,并且是向下滑动
self.bottomView.center = tempCenter;
}
else if(self.bottomView.frame.origin.y < 0)
{
self.bottomView.center = tempCenter;
}
}
}
self.isBeginSlid = NO;
}
else // view显示了需要向上滑动
{
// 获取偏移位置
CGPoint tempCenter;
// 首次触摸进入
if(self.isBeginSlid)
{
if(self.originDirection != HYInteractiveTransitionGestureDirctionNone)
{
return;
}
// 判断是左右滑动还是上下滑动
if(ABS([panGesture translationInView:panGesture.view].x) > ABS([panGesture translationInView:panGesture.view].y))
{
}
else
{
tempCenter = self.bottomView.center;
tempCenter.y += ([panGesture translationInView:panGesture.view].y - self.originY);//上下滑动
self.originY = [panGesture translationInView:panGesture.view].y;
if (self.bottomView.frame.origin.y == 0 && [panGesture translationInView:panGesture.view].y < 0)
{
self.bottomView.center = tempCenter;
}
}
}
// 滑动开始后进入,滑动方向要么水平要么垂直
else
{
if (self.bottomView.frame.origin.y != 0)
{
tempCenter = self.bottomView.center;
tempCenter.y += ([panGesture translationInView:panGesture.view].y - self.originY);//上下滑动
self.originY = [panGesture translationInView:panGesture.view].y;
//禁止向下划
if (self.bottomView.frame.origin.y >= 0 && [panGesture translationInView:panGesture.view].y > 0)
{
//滑动开始是从0点开始的,并且是向下滑动
// self.groupSettingMainView.center = tempCenter;
}
else if(self.bottomView.frame.origin.y < 0)
{
self.bottomView.center = tempCenter;
}
}
}
self.isBeginSlid = NO;
}
}
break;
case UIGestureRecognizerStateEnded:
{
//手势完成后结束标记并且判断移动距离是否过半,过则finishInteractiveTransition完成转场操作,否者取消转场操作
self.interation = NO;
self.isFirst = NO;
if (persent > 0.1)
{
[self finishInteractiveTransition];
}
else
{
[self cancelInteractiveTransition];
}
// 这里添加测试代码
if(self.bottomView.isHiddenView)
{
self.originDirection = HYInteractiveTransitionGestureDirctionNone;
if (self.bottomView.frame.origin.y > -self.vc.view.frame.size.height * 0.8)
{
[UIView animateWithDuration:0.2 animations:^{
CGRect frame = self.bottomView.frame;
frame.origin.y = 0;
self.bottomView.frame = frame;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
self.bottomView.isHiddenView = NO;
});
}];
}
else
{
[UIView animateWithDuration:0.2 animations:^{
CGRect frame = self.bottomView.frame;
frame.origin.y = -self.vc.view.frame.size.height;
self.bottomView.frame = frame;
}];
}
}
else
{
self.originDirection = HYInteractiveTransitionGestureDirctionNone;
if (self.bottomView.frame.origin.y < -self.vc.view.frame.size.height * 0.2)
{
[UIView animateWithDuration:0.2 animations:^{
CGRect frame = self.bottomView.frame;
frame.origin.y = -self.vc.view.frame.size.height;
self.bottomView.frame = frame;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
self.bottomView.isHiddenView = YES;
});
}];
}
else
{
[UIView animateWithDuration:0.2 animations:^{
CGRect frame = self.bottomView.frame;
frame.origin.y = 0;
self.bottomView.frame = frame;
}];
}
}
}
break;
case UIGestureRecognizerStateFailed:
{
}
break;
case UIGestureRecognizerStateCancelled:
{
}
break;
default:
break;
}
}
效果图如下:
demo的github链接
我这种比较笨的方法,实现起来比较复杂,如果有更加简单的方法,可以给我留言,学习一下大神方案,谢谢了。如果有疏漏或者错误的地方,欢迎指正。