這篇文章主要介紹怎樣實現(xiàn)類似系統(tǒng)的測滑返回效果
最終的效果圖為:

Demo地址為:
Demo地址
對應的實現(xiàn)文件為:
EightViewController、CustomPopGestureViewController、PopAnimation
關于轉場動畫,下面這張圖將的很清楚

為了實現(xiàn)類似系統(tǒng)的測滑返回效果,實際上就是pop的自定義返回動畫,再加上UIPanGestureRecognizer手勢的交互實現(xiàn),也就是交互性轉場動畫(因為根據(jù)手指滑動的距離,大于一半會pop到上一個瀏覽器,小于一半會恢復原狀)
由上面的圖可以看到,想要實現(xiàn)交互性轉場動畫,需要實現(xiàn)UIViewControllerInteractiveTransitioning,
但是系統(tǒng)有給我們提供一個可交互的百分比動畫實現(xiàn)類,即UIPerCententDrivenInteractiveTransition,
在接下來的實現(xiàn)中,我們可以直接使用系統(tǒng)提供的實現(xiàn)類,也可以自定義一個遵守UIViewControllerInteractiveTransitioning協(xié)議的類(我們是使用了系統(tǒng)提供的)
首先,我們先把pop動畫的自定義給完成
在eightViewController中,搭建基本的界面,可以push到CustomPopGestureViewController中
在eightViewController.h中
@property (nonatomic, strong) UIButton *button;
在eightViewController.m中
- (void)viewDidLoad {
[super viewDidLoad];
self.title = @"測滑返回手勢測試";
self.navigationController.navigationBar.translucent = NO;
self.view.backgroundColor = [UIColor whiteColor];
self.button.center = self.view.center;
[self.view addSubview:self.button];
}
- (UIButton *)button {
if (_button) {
return _button;
}
_button = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 100, 50)];
[_button setTitle:@"跳轉下一個播放器" forState:UIControlStateNormal];
[_button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[_button addTarget:self action:@selector(buttonClicked) forControlEvents:UIControlEventTouchUpInside];
return _button;
}
- (void)buttonClicked {
NSLog(@"點擊了跳轉按鈕");
CustomPopGestureViewController *vc = [[CustomPopGestureViewController alloc] init];
[self.navigationController pushViewController:vc animated:YES];
}
點擊按鈕,可以push到CustomGestureViewcontroller中
為了實現(xiàn)自定義的測滑返回功能,我們需要禁用系統(tǒng)的測滑返回功能
在CustomViewController中,我們需要添加以下代碼禁用
//禁用系統(tǒng)自帶的側滑返回手勢
self.navigationController.interactivePopGestureRecognizer.enabled = NO;
接下來,先實現(xiàn)pop的自定義動畫
在CustomViewController中,需要遵守UINavigationDelegate協(xié)議
self.navigationController.delegate = self;
實現(xiàn)相應的協(xié)議方法
- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC {
if (operation == UINavigationControllerOperationPop) {
NSLog(@"執(zhí)行了這個方法PopAnimation");
//popAnimation是我們后面定義的類,用來實現(xiàn)具體的動畫效果
return [[PopAnimation alloc] init];
}
return nil;
}
接下來,我們自定義一個類PopAnimation,遵守協(xié)議UIViewControllerAnimatedTransitioning
在類中實現(xiàn)相應的協(xié)議方法
//設置動畫執(zhí)行的時常
- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext {
return 1.0f;
}
//用來處理具體的動畫
- (void)animateTransition:(nonnull id<UIViewControllerContextTransitioning>)transitionContext {
UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
//需要將轉場后的界面給加上去才行
// [[transitionContext containerView] addSubview:toVC.view];
[[transitionContext containerView] insertSubview:toVC.view belowSubview:fromVC.view];
NSTimeInterval duration = [self transitionDuration:transitionContext];
CGFloat width = [UIScreen mainScreen].bounds.size.width;
CGFloat height = [UIScreen mainScreen].bounds.size.height;
[UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
fromVC.view.frame = CGRectMake(width, 0, width, height);
} completion:^(BOOL finished) {
[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
}];
}
上面實現(xiàn)動畫的思路:
我們可以從最終效果圖上可以看成:
pop動畫的過程就是將上面的view向右挪動,直到移出界面
所以代碼中有這一句
[[transitionContext containerView] insertSubview:toVC.view belowSubview:fromVC.view];
將toView的view放在fromVC.view的下面,使用UIview animation來完成移動動畫
注意:這里只能使用UIView animation來完成動畫,代碼中注釋的是我最初使用CABasicAnimation來完成移動動畫,pop自定義動畫可行,但是對于后面使用系統(tǒng)類UIPerCententDrivenInteractiveTransition完成交互不可行,
如果想要使用CaBasicAnimation,必須自定義可交互的百分比動畫類
這樣我們就完成了pop的自定義動畫返回,但是我們需要加入交互,通過判斷手指滑動的距離來判斷動畫的進行程度
接下來,我們需要在CustomPopGestureViewController中,定義相應的手勢屬性和相應的交互類
@property (nonatomic, strong) UIPanGestureRecognizer *pan;
@property (nonatomic, strong) UIPercentDrivenInteractiveTransition *interactiveTransition;
接下來完成相應的手勢類的添加
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.title = @"類似系統(tǒng)側滑返回手勢實現(xiàn)";
self.navigationController.navigationBar.translucent = NO;
self.view.backgroundColor = [UIColor yellowColor];
//禁用系統(tǒng)自帶的側滑返回手勢
self.navigationController.interactivePopGestureRecognizer.enabled = NO;
[self.view addGestureRecognizer:self.pan];
self.navigationController.delegate = self;
}
- (UIPanGestureRecognizer *)pan {
if (_pan) {
return _pan;
}
_pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)];
return _pan;
}
在手勢類的出發(fā)方法中,我們需要根據(jù)UIPanGestureRecognizer的狀態(tài)來初始化或者更新或者取消或者結束交互類
UIGestureRecognizerStateBegan:手勢類剛開始出發(fā)時,初始化相應的interactiveTransition
UIGestureRecognizerStateChanged:手勢繼續(xù)滑動的時候,交互類進行相應的更新
UIGestureRecognizerStateEnded:手勢結束時,交互類結束
UIGestureRecognizerStateCancelled:手勢取消時,交互類取消
最后一個手勢周期完成后都要將交互類interactiveTransition置為nil
代碼為:
- (void)pan:(UIPanGestureRecognizer *)pan {
if (self.navigationController.childViewControllers.count == 1) {
return;
}
CGPoint point = [pan translationInView:self.view];
CGFloat percent = point.x / self.view.bounds.size.width;
NSLog(@"percent的進度值為:%f",percent);
percent = MIN(MAX(0, percent), 1);
if (pan.state == UIGestureRecognizerStateBegan) {
_interactiveTransition = [[UIPercentDrivenInteractiveTransition alloc] init];
[self.navigationController popViewControllerAnimated:YES];
} else if (pan.state == UIGestureRecognizerStateChanged) {
[_interactiveTransition updateInteractiveTransition:percent];
} else if (pan.state == UIGestureRecognizerStateEnded || pan.state == UIGestureRecognizerStateCancelled) {
//手勢結束后,若進度大于0.5就完成pop動畫,否則取消
if (percent > 0.5) {
[_interactiveTransition finishInteractiveTransition];
} else {
[_interactiveTransition cancelInteractiveTransition];
}
_interactiveTransition = nil;
}
}
另外,不要忘記,在UINavigationDelegate協(xié)議方法中實現(xiàn)可交互類的協(xié)議方法
- (id<UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController interactionControllerForAnimationController:(id<UIViewControllerAnimatedTransitioning>)animationController {
if ([animationController isKindOfClass:[PopAnimation class]]) {
NSLog(@"執(zhí)行了這個方法UIPercentDrivenInteractiveTransition");
return _interactiveTransition;
}
return nil;
}
最終的效果圖為:

總結
最終效果圖為:

Demo地址為:
Demo地址
iOS動畫效果的探究二:UIView Animation實現(xiàn)動畫
iOS動畫效果三:CABAsicAnimation實現(xiàn)平移、旋轉和放大
iOS動畫效果五:CABasicAnimation實現(xiàn)繞定點旋轉的效果]