本文記錄分享下自定義轉(zhuǎn)場動畫的實現(xiàn)方法憔儿,具體到動畫效果:新浪微博圖集瀏覽轉(zhuǎn)場效果、手勢過渡動畫、網(wǎng)易音樂啟動屏轉(zhuǎn)場動畫榆俺、開關(guān)門動畫、全屏側(cè)滑返回效果 的代碼可以到Github WSLTransferAnimation下載查看坞淮,注釋還算清晰茴晋。
模態(tài)化present和dismiss 自定義轉(zhuǎn)場
1、創(chuàng)建一個遵循<UIViewControllerAnimatedTransitioning>協(xié)議的動畫過渡管理對象回窘,并實現(xiàn)如下兩個方法:
//返回動畫事件
- (NSTimeInterval)transitionDuration:(nullable id <UIViewControllerContextTransitioning>)transitionContext{
return 0.3;
}
//所有的過渡動畫事務(wù)都在這個方法里面完成
- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext{
//取出轉(zhuǎn)場前后的視圖控制器
UIViewController * fromVC = (UIViewController *)[transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController * toVC = (UIViewController *)[transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
//取出轉(zhuǎn)場前后視圖控制器上的視圖view
UIView * toView = [transitionContext viewForKey:UITransitionContextToViewKey];
UIView * fromView = [transitionContext viewForKey:UITransitionContextFromViewKey];
//這里有個重要的概念containerView诺擅,要做轉(zhuǎn)場動畫的視圖就必須要加入containerView上才能進行,可以理解containerView管理著所有做轉(zhuǎn)場動畫的視圖
UIView *containerView = [transitionContext containerView];
//如果加入了手勢交互轉(zhuǎn)場啡直,就需要根據(jù)手勢交互動作是否完成/取消來做操作烁涌,完成標(biāo)記YES,取消標(biāo)記NO付枫,必須標(biāo)記烹玉,否則系統(tǒng)認(rèn)為還處于動畫過程中,會出現(xiàn)無法交互之類的bug
[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
if ([transitionContext transitionWasCancelled]) {
//如果取消轉(zhuǎn)場
}else{
//完成轉(zhuǎn)場
}
}
2阐滩、自定義一個繼承于UIPercentDrivenInteractiveTransition的手勢過渡管理對象二打,可以根據(jù)手勢需要設(shè)置控制動畫轉(zhuǎn)場進度的百分比。
//必要調(diào)用實現(xiàn)的系統(tǒng)方法
//手勢過程中掂榔,通過updateInteractiveTransition設(shè)置轉(zhuǎn)場過程動畫進行的百分比继效,然后系統(tǒng)會根據(jù)百分比自動布局動畫控件,不用我們控制了
[self updateInteractiveTransition:percentComplete];
//完成轉(zhuǎn)場操作
[self finishInteractiveTransition];
//取消轉(zhuǎn)場操作
[self cancelInteractiveTransition];
3装获、轉(zhuǎn)場時最上層的視圖控制器需要遵循<UIViewControllerTransitioningDelegate>的協(xié)議瑞信,并設(shè)置為代理,并實現(xiàn)如下代理方法:
//設(shè)置轉(zhuǎn)場代理
self.transitioningDelegate = self;
#pragma mark -- UIViewControllerTransitioningDelegate
//返回一個處理present動畫過渡的對象
-(id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source{
return self.transitionAnimation;
}
//返回一個處理dismiss動畫過渡的對象
- (id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed{
//這里我們初始化dismissType
self.transitionAnimation.transitionType = WSLTransitionOneTypeDissmiss;
return self.transitionAnimation;
}
//返回一個處理present手勢過渡的對象
- (nullable id <UIViewControllerInteractiveTransitioning>)interactionControllerForPresentation:(id <UIViewControllerAnimatedTransitioning>)animator{
return self.transitionInteractive;
}
//返回一個處理dismiss手勢過渡的對象
- (nullable id <UIViewControllerInteractiveTransitioning>)interactionControllerForDismissal:(id <UIViewControllerAnimatedTransitioning>)animator{
return self.transitionInteractive;
}
導(dǎo)航控制器push和pop 自定義轉(zhuǎn)場
1穴豫、略...同上
2凡简、略... 同上
3逼友、在push動畫之前設(shè)置導(dǎo)航控制器的轉(zhuǎn)場動畫代理,轉(zhuǎn)場時最上層的視圖控制器需要遵循<UINavigationControllerDelegate>的協(xié)議秤涩,并設(shè)置為代理帜乞,并實現(xiàn)如下代理方法:
//在push動畫之前設(shè)置轉(zhuǎn)場動畫代理
self.navigationController.delegate = animationFour;
#pragma mark -- UINavigationControllerDelegate
//返回處理push/pop動畫過渡的對象
- (nullable id <UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
animationControllerForOperation:(UINavigationControllerOperation)operation
fromViewController:(UIViewController *)fromVC
toViewController:(UIViewController *)toVC{
if (operation == UINavigationControllerOperationPush) {
self.transitionAnimation.transitionType = WSLTransitionTwoTypePush;
return self.transitionAnimation;
}else if (operation == UINavigationControllerOperationPop){
self.transitionAnimation.transitionType = WSLTransitionTwoTypePop;
}
return self.transitionAnimation;
}
//返回處理push/pop手勢過渡的對象 這個代理方法依賴于上方的方法 ,這個代理實際上是根據(jù)交互百分比來控制上方的動畫過程百分比
- (nullable id <UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController
interactionControllerForAnimationController:(id <UIViewControllerAnimatedTransitioning>) animationController{
//手勢開始的時候才需要傳入手勢過渡代理筐眷,如果直接pop或push黎烈,應(yīng)該返回nil,否者無法正常完成pop/push動作
if ( self.transitionAnimation.transitionType == WSLTransitionTwoTypePop) {
return self.transitionInteractive.isInteractive == YES ? self.transitionInteractive : nil;
}
return nil;
}
全屏側(cè)滑返回
創(chuàng)建一個繼承于UINavigationController的一個對象WSLNavigatioController匀谣,遵守協(xié)議<UIGestureRecognizerDelegate>,實現(xiàn)如下方法:
// 獲取系統(tǒng)自帶滑動手勢的target對象
id target = self.interactivePopGestureRecognizer.delegate;
// 創(chuàng)建全屏滑動手勢照棋,調(diào)用系統(tǒng)自帶滑動手勢的target的action方法
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:target action:@selector(handleNavigationTransition:)];
// 設(shè)置手勢代理,攔截手勢觸發(fā)
pan.delegate = self;
// 給導(dǎo)航控制器的view添加全屏滑動手勢
[self.view addGestureRecognizer:pan];
// 禁止使用系統(tǒng)自帶的滑動手勢
self.interactivePopGestureRecognizer.enabled = NO;
#pragma mark -- UIGestureRecognizerDelegate
// 什么時候調(diào)用:每次觸發(fā)手勢之前都會詢問下代理武翎,是否觸發(fā)烈炭。
// 作用:攔截手勢觸發(fā)
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
// 注意:只有非根控制器才有滑動返回功能,根控制器沒有后频。
// 判斷導(dǎo)航控制器是否只有一個子控制器梳庆,如果只有一個子控制器暖途,肯定是根控制器
if (self.childViewControllers.count == 1) {
// 表示用戶在根控制器界面卑惜,就不需要觸發(fā)滑動手勢,
return NO;
}
return YES;
}
解決UIScrollView的滑動手勢與全屏側(cè)滑手勢的沖突
創(chuàng)建一個UIScrollView的類別UIScrollView+GestureConflict驻售,重寫如下方法:
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{
// 首先判斷otherGestureRecognizer是不是系統(tǒng)pop手勢
if ([otherGestureRecognizer.view isKindOfClass:NSClassFromString(@"UILayoutContainerView")]) {
// 再判斷系統(tǒng)手勢的state是began還是fail露久,同時判斷scrollView的位置是不是正好在最左邊
if (otherGestureRecognizer.state == UIGestureRecognizerStateBegan && self.contentOffset.x == 0) {
return YES;
}
}
return NO;
}
更新于 2018/8/17 iOS 全屏側(cè)滑手勢/UIScrollView/UISlider間滑動手勢沖突
推薦閱讀:
http://www.reibang.com/p/45434f73019e
http://www.cocoachina.com/ios/20150811/12897.html
</article>