IOS 自定義push和pop動畫
轉載大神 http://www.cocoachina.com/ios/20150401/11459.html 自iOS7之後,引進了新的API來構造UIViewController之間的轉場動畫,經過幾天的研究,終於做出了一個小Damo,來粗淺談談。 這幾個API如下: <1.>UIViewControllerAnimatedTransitioning 動畫協議 <2>.UIViewControllerInteractiveTransitioning 互動協議 <3>.UIViewControllerContextTransitioning 上下文協議 <4>.UIPercentDrivenInteractiveTransition 遵守 <2>協議的一個官方類 之所以官方給出的API是協議而不是類別,給出的說法是為了靈活性,你可以在ViewController裡面直接寫,也可以直接另寫一個類封裝起來。 進入正文: 1、 這個類負責動畫,繼承自NSObject,遵守UIViewControllerAnimatedTransitioning協議,記得匯入UIKit,如下 @interface PopAnimation : NSObject <UIViewControllerAnimatedTransitioning> @end 在.m檔案中實現協議其中的兩個方法: (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext { //這個方法返回動畫執行的時間 return 0.25;
}
/** transitionContext你可以看作是一個工具,用來獲取一系列動畫執行相關的物件,並且通知系統動畫是否完成等功能。 */ (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext { /** 獲取動畫來自的那個控制器 */ UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; /** 獲取轉場到的那個控制器 */ UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; /** 轉場動畫是兩個控制器檢視時間的動畫,需要一個containerView來作為一個“舞臺”,讓動畫執行。 */ UIView *containerView = [transitionContext containerView]; [containerView insertSubview:toViewController.view belowSubview:fromViewController.view]; NSTimeInterval duration = [self transitionDuration:transitionContext]; // /** // * 執行動畫,我們讓fromVC的檢視移動到螢幕最右側 // */ // [UIView animateWithDuration:duration animations:^{ // fromViewController.view.transform = CGAffineTransformMakeTranslation([UIScreen mainScreen].bounds.size.width, 0); }completion:^(BOOL finished) { /** // * 當你的動畫執行完成,這個方法必須要呼叫,否則系統會認為你的其餘任何操作都在動畫執行過程中。 // */ // [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]; // //----------------pop動畫二-------------------------// // // CATransition *tr = [CATransition animation]; // tr.type = @"cube"; // tr.subtype = @"fromLeft"; // tr.duration = duration; // tr.removedOnCompletion = NO; // tr.fillMode = kCAFillModeForwards; // tr.delegate = self; // [containerView.layer addAnimation:tr forKey:nil]; // [containerView exchangeSubviewAtIndex:0 withSubviewAtIndex:1]; } *在pop過程中可使用動畫,例如 _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]; Push基類.m 第一個方法返回的是動畫時間,不做多言。 第二個方法是動畫的具體執行,方法的引數transitionContext遵守了UIViewControllerContextTransitioning協議,所以它包含了許多關於專場所需要的內容,包括轉入ViewController和轉出Viewcontroller,還有動畫容器View--containerView等。 我們點進去UIViewControllerContextTransitioning協議,可以找到許多的屬性和方法,這些方法中最重要的幾個方法和意義如下: (UIView*)containerView; //獲取容器View (void)completeTransition:(BOOL)didComplete;//通過此引數獲知動畫是否結束 (UIViewController*)viewControllerForKey:(NSString*)key; //獲取轉入、轉出VC (CGRect)initialFrameForViewController:(UIViewController*)vc //獲取動畫前VC的frame (CGRect)finalFrameForViewController:(UIViewController*)vc; //獲取動畫後VC的frame (push的基類也和pop一樣,只是具體動畫效果程式碼的不同) 另外,我們需要返回一個遵守了UIViewControllerInteractiveTransitioning協議的物件(提示一下,這兩個協議容易混淆,要注意區分,一個是負責動畫,一個是負責互動過程),蘋果已經有一個類專門處理這個功能,它叫UIPercentDrivenInteractiveTransition,當然你也可以自定義一個這樣的類。我們可以這樣理解它的作用:前面在方法1中返回的動畫,會在執行的過程中被系統分解以用於使用者互動,這個互動過程的動畫完成度就由它來調控。下面我們來看一下如何使用它。(為了讓控制器檢視拖動,我們給控制器的檢視加了一個拖動手勢,在拖動方法裡我們對這個物件進行操作) 定義一個類,NavigationInteractiveTransition ,實現 .h中 @class UIViewController, UIPercentDrivenInteractiveTransition; @interface NavigationInteractiveTransition : NSObject <UINavigationControllerDelegate> (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動畫的執行 */ (void)handleControllerPop:(UIPanGestureRecognizer *)recognizer { /* interactivePopTransition就是我們說的方法2返回的物件,我們需要更新它的進度來控制Pop動畫的流程,我們用手指在檢視中的位置與檢視寬度比例作為它的進度。 */ CGFloat progress = [recognizer translationInView:recognizer.view].x / recognizer.view.bounds.size.width; /** 穩定進度區間,讓它在0.0(未完成)~1.0(已完成)之間 */ progress = MIN(1.0, MAX(0.0, progress)); if (recognizer.state == UIGestureRecognizerStateBegan) { /** 手勢開始,新建一個監控物件 */ self.interactivePopTransition = [[UIPercentDrivenInteractiveTransition alloc] init]; /** 告訴控制器開始執行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) { [UIView animateWithDuration:0.3 animations:^{ [self.interactivePopTransition finishInteractiveTransition]; }completion:^(BOOL finished) { self.interactivePopTransition = nil; }]; } else { [UIView animateWithDuration:0.3 animations:^{ [self.interactivePopTransition cancelInteractiveTransition]; }completion:^(BOOL finished) { self.interactivePopTransition = nil; }]; } } } 然後初始化pop動畫類 (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC { /** 方法1中判斷如果當前執行的是Pop操作,就返回我們自定義的Pop動畫物件。 */ if (operation == UINavigationControllerOperationPop) return [[PopAnimation alloc] init]; return nil; } 最後,自定義一個整合UINavigationcontroller的類來使用 #import "NavigationInteractiveTransition.h" @interface Nav () <UIGestureRecognizerDelegate> @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 { /** 這裡有兩個條件不允許手勢執行,1、當前控制器為根控制器;2、如果這個push、pop動畫正在執行(私有屬性) */ return self.viewControllers.count != 1 && ![[self valueForKey:@"_isTransitioning"] boolValue]; } 接下來就可以使用了,push和pop的方法一樣,只是在例項化的時候注意區分 (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC { /** 方法1中判斷如果當前執行的是Pop操作,就返回我們自定義的Pop動畫物件。 */ if (operation == UINavigationControllerOperationPop) return [[PopAnimation alloc] init]; else if (operation == UINavigationControllerOperationPush) return [[PushAnimation alloc] init]; return nil; } 常見問題: 經常會遇到,橫向翻頁的scrollview和滑動手勢衝突,那麼 1.首先自定義一個scrollView,比如:CustomScrollView,遵守協議,然後在實現檔案中寫如下程式碼: -(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
// 首先判斷otherGestureRecognizer是不是系統pop手勢 if ([otherGestureRecognizer.view isKindOfClass:NSClassFromString(@"UILayoutContainerView")]) { // 再判斷系統手勢的state是began還是fail,同時判斷scrollView的位置是不是正好在最左邊 if (otherGestureRecognizer.state == UIGestureRecognizerStateBegan && self.contentOffset.x == 0) { return YES; } } return NO; } 2.那個橫向滾動的scrollView繼承這個自定義scrollView,也就是CustomScrollView
相關推薦
IOS 自定義push和pop動畫
轉載大神 http://www.cocoachina.com/ios/20150401/11459.html 自iOS7之後,引進了新的API來構造UIViewController之間的轉場動畫,經過幾天的研究,終於做出了一個小Damo,來粗淺談談。
Swift基礎之自定義PUSH和POP跳轉動畫
之前用OC程式碼寫過PUSH和POP的轉場動畫,閒來無事,將其轉換成Swift語言,希望對大家有幫助,轉載請註明。。。。如何實現PUSH和POP的轉場動畫?首先,建立一個NSObject的類,分別用來實現PUSH和POP的動畫效果建立PUSH檔案,實現扇形效果,程式碼如下:需
iOS自定義轉場動畫(1)——自定義Push轉場動畫
版本:Xcode 7.0.1 語言:Objective-C 轉場動畫就是viewController之間切換的動畫。 主要有以下三種自定義方法: 列Push & Pop Modal Segue 第一種是UINavigationControl
iOS pushViewController 實現push 和pop 預設動畫效果
一、push預設動畫效果 CATransition *transition = [CATransitionanimation]; transition.duration = 0.3f; transition.timingFunction = [CAM
iOS 自定義雷達 掃描/擴散動畫 View
前段時間 沒事兒,自己自定義了 一個雷達掃描/擴散效果的View。 掃描View 效果如下: 擴散View 效果如下: 自定義的程式碼如下: 1. RadarView.h #import <UIKit/UIKit.h> typedef NS_ENUM(
iOS 自定義日期和資料來源選擇控制元件
需求 App開發中經常會有日期選擇(如生日、睡眠定時等)或者省市區選擇等此類功能,通常UI中不會單獨使用UI中的控制元件,而是在UIPickerView的基礎上增加一個取消和確定按鈕 特點 支援常見的選擇型的資料格式 該控制元件集成了 yyyy-M
iOS 自定義導航欄pop返回手勢,全屏右滑返回
- (void)viewDidLoad { [superviewDidLoad]; //重新給interactivePopGestureRecognizer.delegate掛代理
iOS自定義轉場動畫
http://www.jianshu.com/p/45434f73019e 更新,更簡單的自定義轉場整合! 寫在前面 這兩天閒下來好好的研究了一下自定義轉場,關於這方面的文章網路上已經很多了,作為新手,我想通過這篇文章把自己這幾天的相關學習心得記錄一下,方便加深印響和
iOS xcode 生成 自定義註釋和API
//聯絡人:石虎 QQ:1224614774 暱稱:嗡嘛呢叭咪哄 一、概念 Objective-C寫程式碼時有三種可能的方法來標示一個註釋文件區域: 1. 把你的註釋包含在/** –
IOS百度地圖自定義大頭針和氣泡
文/煜寒了(簡書作者) 原文連結:http://www.jianshu.com/p/6a334f071c69 著作權歸作者所有,轉載請聯絡作者獲得授權,並標註“簡書作者”。1.首先實現新增多個標註和自定義氣泡 新增自定義標註 [_mapView addAnnotations:array]; arry 中放入標
iOS 自定義載入等待動畫
一般來說,我們的專案中請求網路資料是一個比較耗時的操作,在請求的過程中如果給使用者只展示空白的頁面或者預設的頁面,難免顯得有些單調,這個時候我們可以新增一個指示動畫,開始請求的時候執行動畫,資料請求下來了停止動畫,這樣使用者體驗會好一些。下面開始自定義我們自己的載入指示動畫
自定義dialog和彈出dialog的動畫
自定義dialog final Dialog dialog = new Dialog(ChartVisit.this); LayoutInflater inflater=getLayoutInflater();
【轉】自定義presentviewcontroller和pushviewcontroller轉場動畫
自定義NavigationController動畫 首先,實現一個非常簡單的UINavigationController轉場,一般會這麼幹 實現FirstViewController,加到Window上(沒用storyboard和xib) 實現FirstViewCo
IOS 自定義導航欄和標籤欄
大多數ios應用都是以標籤欄加導航欄的形式呈現,一般根控制器都是UIToolbar,然後再以UINavigationController為子控制器,然後再加入UIViewController。為什麼要這樣?因為不同的標籤欄的項一般對應不同的功能,那麼導航欄的標題一般就不同。
iOS自定義tabbar後popToRootViewContriller和poptoviewcontroller時出現兩個tabbar 的解決辦法
iOS自定義tabbar後popToRootViewContriller和poptoviewcontroller時出現兩個tabbar 的解決辦法 問題:iOS自定義tabbar後popToRootViewContriller和poptoviewcontroller時出
iOS自定義轉場動畫(4)——自定義模態跳轉之dismiss與手勢驅動
Dismiss 效果: 1、新建PresentTransition繼承NSObject,並在.h中遵守UIViewControllerAnimatedTransitioning協議。 2、實現協議的兩個方法,並在其中編寫 Push 的動畫。類似Pr
iOS 中自定義cell和控制器之間常用傳值方式
自定義cell和控制器之間常用傳值方式 1.代理傳值(用的多) 在自定義cell的.h檔案中制定協議,例: @class OtherTableViewCell; @protocol OtherTableViewCellDelegate <NSObject&g
ios 自定義鍵盤的return鍵以及鍵盤的其他一些屬性
variable 位置 arch ext ddr gin character 觸發 hone //初始化textfield並設置位置及大小 UITextField *text = [[UITextField alloc]initWithFrame:CGRectMake(20
IOS 自定義按鈕(代碼實現)+九宮格
uifont 排列 end uiview height iyu void rec name 在一些下載應用裏整個頁面都是按鈕,有好多好多,但是仔細觀察不難發現他們很有規律。就像下面一樣?? 很有規律的排列在屏幕上,那麽這需要我們怎麽去做能。 正如標題,我們需要了解兩個知
iOS自定義一些提示控件
mat cat get -1 from start mask ins sel 代碼如下: .h中的代碼: // // HKUIToolsView.h // HKUIToolsDemo // // Created by isHakan on 2017/7/28