這次我要記錄的是跟“presentViewController”有關
- [self.navigationController presentViewController:self.viewCtrl animated:YES completion:NULL];
對!就是上面這個!!
在我原本認知中,這是個一行搞定的簡單函示,但沒想到可以有延伸的應用
我是從這篇 http://jackyeh.logdown.com/posts/240412-ios-custom-viewcontroller-transition 跟其他網路上的資料學習的,主要是網址這篇
首先你可以創個 customPresentAnimation.h 跟 customPresentAnimation.m
customPresentAnimation.h 裡
- @interface customPresentAnimation : NSObject<UIViewControllerAnimatedTransitioning>
- @property (assign, nonatomic )BOOL appearing;
- @end
h檔裡這樣就好了appearing 是我拿來判斷是要 出現 還是 消失 用的
有些人會把出現跟消失的動畫分成兩個檔案來寫,但我這個人比較懶惰,所以我決定把他們寫在一起
m檔裡要這些
- - (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext
- {
- return 1.0;
- }
- - (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
- {
- UIViewController *viewControllerA = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
- UIViewController *viewControllerB = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
- UIView *fromView = viewControllerA.view;
- UIView *toView = viewControllerB.view;
- UIView *containerView = [transitionContext containerView];
- NSTimeInterval duration = [self transitionDuration:transitionContext];
- CGRect initialFrame = [transitionContext initialFrameForViewController:viewControllerA];
- CGRect offscreenRect = CGRectOffset(initialFrame, 0, -[UIScreen mainScreen].bounds.size.height);
- // Presenting
- if (self.appearing) {
- // Position the view offscreen
- toView.frame = offscreenRect;
- [containerView addSubview:toView];
- // Animate the view onscreen
- [UIView animateWithDuration:duration
- delay:0
- usingSpringWithDamping:0.5
- initialSpringVelocity:1
- options:0
- animations: ^{
- toView.frame = initialFrame;
- } completion: ^(BOOL finished) {
- [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
- }];
- }
- // Dismissing
- else {
- [containerView addSubview:toView];
- [containerView sendSubviewToBack:toView];
- // Animate the view offscreen
- [UIView animateWithDuration:duration
- delay:0
- usingSpringWithDamping:0.5
- initialSpringVelocity:1
- options:0
- animations: ^{
- fromView.frame = offscreenRect;
- } completion: ^(BOOL finished) {
- [fromView removeFromSuperview];
- [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
- }];
- }
- }
這裡的m檔 我先用網址裡的範例說明
- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext
這個是拿來回傳動畫的時間
接著
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
這個是要寫兩個viewCtrl切換的動畫的地方
UITransitionContextFromViewControllerKey
這個key可以抓出From的View
UITransitionContextToViewControllerKey
這個key可以抓出to的View
ex: viewCtrlA 要 present viewCtrlB
FromView 就是 viewCtrlA
toView 就是 viewCtrlB
再來就是寫動畫的時間啦~~~~
然後最重要的一點就是
[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
這行!
一定要在動畫完以後才執行,否則可能會影響到你的動畫美觀程度
例如我自己是在 if (self.appearing) 這裡面執行不同的動畫
- toView.frame = initialFrame;
- toView.center = CGPointMake( [UIScreen mainScreen].bounds.size.width / 2 ,[UIScreen mainScreen].bounds.size.height / 2);
- [containerView addSubview:toView];
- // Animate the view onscreen
- CALayer *viewLayer = toView.layer;
- CAKeyframeAnimation* animation = [CAKeyframeAnimation animationWithKeyPath:@"transform.scale"];
- animation.delegate = self;
- animation.duration = duration;
- animation.values = [NSArray arrayWithObjects:
- [NSNumber numberWithFloat:0.1],
- [NSNumber numberWithFloat:1.1],
- [NSNumber numberWithFloat:.9],
- [NSNumber numberWithFloat:1],
- nil];
- animation.keyTimes = [NSArray arrayWithObjects:
- [NSNumber numberWithFloat:0.0],
- [NSNumber numberWithFloat:0.6],
- [NSNumber numberWithFloat:0.8],
- [NSNumber numberWithFloat:1.0],
- nil];
- [viewLayer addAnimation:animation forKey:@"transform.scale"];
我是執行像這樣從中間跳出視窗放大彈跳的感覺
如果我把 “ [transitionContext completeTransition:![transitionContext transitionWasCancelled]]; ”這行在24行地方執行的話
會在彈跳放大前 FromView 就被覆蓋拿掉了,彈跳前背景就變成白色
所以這時候就要
animation.delegate = self;
這行讓我去觸發動畫結束的函示
- - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
- {
- [self.transitionContext completeTransition:![self.transitionContext transitionWasCancelled]];
- }
我這裡才去執行
這樣彈跳出來的動畫就完美啦~~~
當然這樣你也只是完成這兩個 .h 跟 .m 檔而已
還要去使用囉
//***********************************************************************//
下面就來說如何去呼叫
在你要使用到 presnet 的那個 ViewCtrlA 當然要去 import 他,ViewCtrlB 也要import
所以要添加
- #import "customPresentAnimation.h"
這行
-------------------------------------------------------------------------------------------------------------------
接著要使用到 UIViewControllerTransitioningDelegate 這個
所以要添加
- @interface ViewCtrl ()<UIViewControllerTransitioningDelegate>
在這裡添加
ViewCtrlA 跟 ViewCtrlB 都要添加
-------------------------------------------------------------------------------------------------------------------
然後這行看你要在哪裡添加
- viewCtrlB.transitioningDelegate = self;
則 viewCtrlB 裡添加
- self.transitioningDelegate = self;
我自己是在 - (void)viewDidLoad 裡分配空間時就順便設置了
-------------------------------------------------------------------------------------------------------------------
viewCtrlA 裡要添加
- - (id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented
- presentingController:(UIViewController *)presenting
- sourceController:(UIViewController *)source
- {
- customPresentAnimation *animator = [[customPresentAnimation alloc]init];
- animator.appearing = YES;
- return animator;
- }
viewCtrlB 裡要添加
- - (id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed {
- customPresentAnimation *animator = [[customPresentAnimation alloc]init];
- animator.appearing = NO;
- return animator;
- }
-------------------------------------------------------------------------------------------------------------------
接著在你要 Present 的地方如往常的呼叫
- [self.navigationController presentViewController:viewCtrlB animated:YES completion:NULL];
要 Dismissing 的地方呼叫
- [self dismissViewControllerAnimated:YES completion:NULL];
這樣子就大功告成啦!!!
網址裡還有其他的應用,有空大家也可以再去研究一下,改天比較閒時,我也會回去看的!!
沒有留言:
張貼留言