IOS push和pop 自定義動畫

轉載大神? ? http://www.cocoachina.com/ios/20150401/11459.html

? ? ? 自iOS7之后泻拦,引進了新的API來構造UIViewController之間的轉場動畫忽媒,經(jīng)過幾天的研究,終于做出了一個小Damo架曹,來粗淺談談。這幾個API如下:

<1.>UIViewControllerAnimatedTransitioning? 動畫協(xié)議<2>.UIViewControllerInteractiveTransitioning? 交互協(xié)議<3>.UIViewControllerContextTransitioning? ? ? 上下文協(xié)議<4>.UIPercentDrivenInteractiveTransition? ? ? ? 遵守? ?

? ? ? 協(xié)議的一個官方類之所以官方給出的API是協(xié)議而不是類別绑雄,給出的說法是為了靈活性,你可以在ViewController里面直接寫罗珍,也可以直接另寫一個類封裝起來脚粟。進入正文:

? ? ? 1、? 這個類負責動畫扣唱,繼承自NSObject画舌,遵守UIViewControllerAnimatedTransitioning協(xié)議已慢,記得導入UIKit,如下

? ? ? @interface PopAnimation : NSObject<UIViewControllerAnimatedTransitioning>

? ? ? @end

? ? ? 在.m文件中實現(xiàn)協(xié)議其中的兩個方法: ? ? ??

? ? ? -(NSTimeInterval)transitionDuration:(id)transitionContext?

{

? ? ? //這個方法返回動畫執(zhí)行的時間

? ? ? return 0.25;

}

? ? ? -(void)animateTransition:(id)transitionContext

?{

? ? ? /** transitionContext你可以看作是一個工具朋腋,用來獲取一系列動畫執(zhí)行相關的對象膜楷,并且通知系統(tǒng)動畫是否完成等功能。*/

? ? ?/**? 獲取動畫來自的那個控制器 */

? ? ? ? ? ? UIViewController *fromViewController = [transitionContext ? ? viewControllerForKey:UITransitionContextFromViewControllerKey];

? ? ?/**? 獲取轉場到的那個控制器 */

? ? ? ? ? ?UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];

? ? ? /**? 轉場動畫是兩個控制器視圖時間的動畫穷绵,需要一個containerView來作為一個“舞臺”仲墨,讓動畫執(zhí)行揍障。 */

? ? ? UIView *containerView = [transitionContext containerView]; ?

? ? ? [containerView insertSubview:toViewController.view belowSubview:fromViewController.view];

? ? ? NSTimeInterval duration = [self transitionDuration:transitionContext];

? ? ? /**//? ? *? 執(zhí)行動畫,我們讓fromVC的視圖移動到屏幕最右側//? ? */ ? ? ??

? ? ? [UIView animateWithDuration:duration? animations:^{ ? ? ? ? ??

? ? ? ? ? ? ?fromViewController.view.transform =?

? ? ? ? ? ? ?CGAffineTransformMakeTranslation([UIScreen mainScreen].bounds.size.width, 0);}completion:^(BOOL finished) {??

? ? ? ? ? ? /**//? ? ? ? *? 當你的動畫執(zhí)行完成癌蚁,這個方法必須要調(diào)用,否則系統(tǒng)會認為你的其余任何操作都在動畫執(zhí)行過程中碘梢。//? ? ? ? */

?? ? ? ?[transitionContext completeTransition:!transitionContext.transitionWasCancelled];

?? ?}];

也可以使用動畫

? ? ? ?_transitionContext = transitionContext;

? ? ? //? ? ----------------pop動畫一------------------------- ? ? ??

? ? ? ? [UIView beginAnimations:@"View Flip" context:nil];

? ? ? ? [UIView setAnimationDuration:duration];[UIView setAnimationDelegate:self];

? ? ? ? [UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:containerView cache:YES];

? ? ? ? [UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:)];

? ? ? ? [UIView commitAnimations];//提交UIView動畫

? ? ? ? [containerView exchangeSubviewAtIndex:0 withSubviewAtIndex:1];

? ? ? ? ?第一個方法返回的是動畫時間痘系,不做多言饿自。第二個方法是動畫的具體執(zhí)行昭雌,方法的參數(shù)transitionContext遵守了UIViewControllerContextTransitioning協(xié)議健田,所以它包含了許多關于專場所需要的內(nèi)容,包括轉入ViewController和轉出Viewcontroller总放,還有動畫容器View--containerView等好爬。我們點進去UIViewControllerContextTransitioning協(xié)議,可以找到許多的屬性和方法炬搭,這些方法中最重要的幾個方法和意義如下:

? ? ? ? (UIView*)containerView;? //獲取容器View ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??

? ? ? ? (void)completeTransition:(BOOL)didComplete;//通過此參數(shù)獲知動畫是否結束? ? ? ? ? ? ? ? ?

? ? ? ? (UIViewController*)viewControllerForKey:(NSString*)key;? //獲取轉入宫盔、轉出VC

? ? ? ? (CGRect)initialFrameForViewController:(UIViewController*)vc? //獲取動畫前VC的frame

? ? ? ? (CGRect)finalFrameForViewController:(UIViewController*)vc;? ? //獲取動畫后VC的frame

? ? ? ? (push的基類也和pop一樣享完,只是具體動畫效果代碼的不同)

? ? ? ? 另外,我們需要返回一個遵守了UIViewControllerInteractiveTransitioning協(xié)議的對象(提示一下彼绷,這兩個協(xié)議容易混淆倒源,要注意區(qū)分,一個是負責動畫热某,一個是負責交互過程),蘋果已經(jīng)有一個類專門處理這個功能筹吐,它叫UIPercentDrivenInteractiveTransition秘遏,當然你也可以自定義一個這樣的類。我們可以這樣理解它的作用:

? ? ? ?前面在方法1中返回的動畫洋侨,會在執(zhí)行的過程中被系統(tǒng)分解以用于用戶交互倦蚪,這個交互過程的動畫完成度就由它來調(diào)控。

? ? ? 下面我們來看一下如何使用它裁僧。(為了讓控制器視圖拖動慕购,我們給控制器的視圖加了一個拖動手勢,在拖動方法里我們對這個對象進行操作)定義一個類获洲,NavigationInteractiveTransition 可训,實現(xiàn):

? ? ?.h中

? ? ?@class UIViewController,UIPercentDrivenInteractiveTransition;

? ? ?@interface NavigationInteractiveTransition : NSObject

? ? ? -(instancetype)initWithViewController:(UIViewController *)vc;- ?

? ? ? -(void)handleControllerPop:(UIPanGestureRecognizer *)recognizer;

? ? ? -(UIPercentDrivenInteractiveTransition *)interactivePopTransition;

@end

? ? .m中設置導航控制器的delegate為這個自定義的類

? ? ? @interface NavigationInteractiveTransition ()

? ? ? @property (nonatomic, weak) UINavigationController *vc;

? ? ? @property (nonatomic, strong) UIPercentDrivenInteractiveTransition *interactivePopTransition;

? ? ? @end

? ? ? @implementation NavigationInteractiveTransition ??

? ? ? -(instancetype)initWithViewController:(UIViewController *)vc

{

? ? ? self = [super init];

? ? ? if (self) {??

? ? ? ? ? ? ? ? ? ?self.vc = (UINavigationController *)vc;? ?

? ? ? ? ? ? ? ? ? ? self.vc.delegate = self;

? ? ? ?}

? ? ? ? return self;

}

? ? ? ?添加手勢代理/*? 我們把用戶的每次Pan手勢操作作為一次pop動畫的執(zhí)行 */

? ? ? ?-(void)handleControllerPop:(UIPanGestureRecognizer *)recognizer {

? ? ? ?/*? interactivePopTransition就是我們說的方法2返回的對象握截,我們需要更新它的進度來控制Pop動畫的流程,我們用手指在視圖中的位置與視圖寬度比例作為它的進度固歪。 */

? ? ? ?CGFloat progress = [recognizer translationInView:recognizer.view].x / recognizer.view.bounds.size.width;

? ? ? ? ?/**? 穩(wěn)定進度區(qū)間胯努,讓它在0.0(未完成)~1.0(已完成)之間 */

? ? ? ? ? progress = MIN(1.0, MAX(0.0, progress));

? ? ? ? ? if (recognizer.state == UIGestureRecognizerStateBegan) {?

? ? ? ? ? ? /**? ? ? 手勢開始,新建一個監(jiān)控對象? ? */? ??

? ? ? ? ? ? ? ? ? ? ?self.interactivePopTransition = [[UIPercentDrivenInteractiveTransition alloc] init];??

? ? ? ? ? ? ?/**? ? ? 告訴控制器開始執(zhí)行pop的動畫? ? */??

? ? ? ? ? ? ? ? ? ? ? ?[self.vc popViewControllerAnimated:YES];

? ? ? ? ? ? ?}else if (recognizer.state == UIGestureRecognizerStateChanged) {??

? ? ? ? ? ? ? ? ? ? ? ?/**? ? ? 更新手勢的完成進度? ? */? ?

? ? ? ? ? ? ? ? ? ? ? ? [self.interactivePopTransition updateInteractiveTransition:progress];

? ? ? ? ? ? }else if (recognizer.state == UIGestureRecognizerStateEnded || recognizer.state == UIGestureRecognizerStateCancelled) {?

? ? ? ? ? ? ? ? ? ? ? ? ? /**? ? ? 手勢結束時如果進度大于一半蒲讯,那么就完成pop操作判帮,否則重新來過。? ? */? ?

? ? ? ? ? ? ? ? ? ? ? ? ? if (progress > 0.3) {??

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? [self.interactivePopTransition finishInteractiveTransition]; ? ? ? ? ? ? ? ?

? ? ? ? ? ? ? ? ? ? ? ? ? }? ? else {?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?[self.interactivePopTransition cancelInteractiveTransition]; ? ? ?

? ? ? ? ? ? ? ? ? ? ? ? ? ?}

? ? ? ? ? ? ? ? ? ? ? ? ? self.interactivePopTransition = nil; ??

? ? ? ? ? ? ? ? }

}??

? ? ? ?然后初始化pop動畫類 ? ?

? ? ? ?-(id)navigationController:(UINavigationController *)navigationController? ? ? ? ? ? ? ? ? ? ? ? ? ? ? animationControllerForOperation:(UINavigationControllerOperation)operation? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? fromViewController:(UIViewController *)fromVC? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? toViewController:(UIViewController *)toVC {

? ? ? ? ? ?/**? 方法1中判斷如果當前執(zhí)行的是Pop操作悦昵,就返回我們自定義的Pop動畫對象晌畅。 */

? ? ? ? ? ?if (operation == UINavigationControllerOperationPop)? ? return [[PopAnimation alloc] init];return nil;

?}

? ? ? ? ? 最后,自定義一個集成UINavigationcontroller的類來使用

? ? ? ? ? #import "NavigationInteractiveTransition.h"

? ? ? ? ? @interface Nav ()@property (nonatomic, weak) UIPanGestureRecognizer *popRecognizer;

? ? ? ? ? @property (nonatomic, strong) NavigationInteractiveTransition *navT;

? ? ? ? ? @end

? ? ? ? ? @implementation Nav

? ? ? ? ? -(void)viewDidLoad

?{

? ? ? ? ? ?[super viewDidLoad];

? ? ? ? ? ?UIGestureRecognizer *gesture = self.interactivePopGestureRecognizer;

? ? ? ? ? ?gesture.enabled = NO;

? ? ? ? ? ?UIView *gestureView = gesture.view;

? ? ? ? ? ?UIPanGestureRecognizer *popRecognizer = [[UIPanGestureRecognizer alloc] init];

? ? ? ? ? ? popRecognizer.delegate = self;popRecognizer.maximumNumberOfTouches = 1;

? ? ? ? ? ? [gestureView addGestureRecognizer:popRecognizer];

? ? ? ? ? ?_navT = [[NavigationInteractiveTransition alloc] initWithViewController:self];

? ? ? ? ? ? [popRecognizer addTarget:_navT action:@selector(handleControllerPop:)];

}

? ? ? ? ? - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer?

{

? ? ? ? ? ?/**? 這里有兩個條件不允許手勢執(zhí)行棋凳,1贫橙、當前控制器為根控制器;2、如果這個push疲迂、pop動畫正在執(zhí)行(私有屬性) */

? ? ? ? ? ?return self.viewControllers.count != 1 && ![[self valueForKey:@"_isTransitioning"] boolValue];

}

? ? ? ? ? 接下來就可以使用了,push和pop的方法一樣郑气,只是在實例化的時候注意區(qū)分

? ? ? ? ? ? -(id)navigationController:(UINavigationController *)navigationController

animationControllerForOperation:(UINavigationControllerOperation)operation

fromViewController:(UIViewController *)fromVC

toViewController:(UIViewController *)toVC {

/**

方法1中判斷如果當前執(zhí)行的是Pop操作尾组,就返回我們自定義的Pop動畫對象。

*/

if (operation == UINavigationControllerOperationPop)

return [[PopAnimation alloc] init];

else if (operation == UINavigationControllerOperationPush)

return [[PushAnimation alloc] init];

return nil;

}

常見問題:

經(jīng)常會遇到讳侨,橫向翻頁的scrollview和滑動手勢沖突跨跨,那么

1.首先自定義一個scrollView,比如:CustomScrollView勇婴,遵守協(xié)議嘱腥,然后在實現(xiàn)文件中寫如下代碼:

-(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;

}

2.那個橫向滾動的scrollView繼承這個自定義scrollView橱脸,也就是CustomScrollView

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市椭盏,隨后出現(xiàn)的幾起案子吻商,更是在濱河造成了極大的恐慌,老刑警劉巖乌叶,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件柒爸,死亡現(xiàn)場離奇詭異,居然都是意外死亡乐横,警方通過查閱死者的電腦和手機今野,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來催什,“玉大人宰睡,你說我怎么就攤上這事⌒玻” “怎么了?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵臂聋,是天一觀的道長孩等。 經(jīng)常有香客問我采够,道長,這世上最難降的妖魔是什么蹬癌? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任,我火速辦了婚禮隅要,結果婚禮上,老公的妹妹穿的比我還像新娘步清。我一直安慰自己,他們只是感情好欢搜,可當我...
    茶點故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布炒瘟。 她就那樣靜靜地躺著,像睡著了一般疮装。 火紅的嫁衣襯著肌膚如雪粘都。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天,我揣著相機與錄音做个,去河邊找鬼。 笑死顽频,一個胖子當著我的面吹牛太闺,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播省骂,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼钞澳,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了轧粟?” 一聲冷哼從身側響起脓魏,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤茂翔,失蹤者是張志新(化名)和其女友劉穎履腋,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體府树,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡奄侠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了烹卒。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片弯洗。...
    茶點故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖藐吮,靈堂內(nèi)的尸體忽然破棺而出逃贝,到底是詐尸還是另有隱情,我是刑警寧澤沐扳,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布沪摄,位于F島的核電站,受9級特大地震影響杨拐,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜哄陶,卻給世界環(huán)境...
    茶點故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一奕筐、第九天 我趴在偏房一處隱蔽的房頂上張望变骡。 院中可真熱鬧芭逝,春花似錦、人聲如沸旬盯。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽萨咳。三九已至,卻和暖如春培他,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背俊扳。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工猛遍, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人懊烤。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓奸晴,卻偏偏與公主長得像日麸,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子代箭,可洞房花燭夜當晚...
    茶點故事閱讀 42,722評論 2 345

推薦閱讀更多精彩內(nèi)容