iOS自定義轉(zhuǎn)場(chǎng)動(dòng)畫-2

上一篇文章介紹了三種簡(jiǎn)單的轉(zhuǎn)場(chǎng)動(dòng)畫,全部代碼在這里
這里說(shuō)另外兩種

Untitled-1.gif
第一種動(dòng)畫(AdaptivePresentation)

其實(shí)乍一看這個(gè)從底部彈出來(lái)的感覺不就是Modal么,對(duì),沒錯(cuò),用Modal可以很簡(jiǎn)單的實(shí)現(xiàn)。但是既然說(shuō)自定義,那就看看是怎么自定義出來(lái)的。附圖Modal的效果,在目標(biāo)控制器插入一個(gè)NavigationController就能實(shí)現(xiàn)了。

Untitled-modal效果.gif

首先目標(biāo)控制器要遵循UIAdaptivePresentationControllerDelegate協(xié)議

- (void)setTransitioningDelegate:(id<UIViewControllerTransitioningDelegate>)transitioningDelegate{
    [super setTransitioningDelegate:transitioningDelegate];
    self.presentationController.delegate = self;
}

#pragma mark-  UIAdaptivePresentationControllerDelegate
- (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller{
    return UIModalPresentationFullScreen;
}
- (UIViewController *)presentationController:(UIPresentationController *)controller viewControllerForAdaptivePresentationStyle:(UIModalPresentationStyle)style{
    return [[UINavigationController alloc]initWithRootViewController:controller.presentedViewController];
}

說(shuō)個(gè)插曲,由于用的是storyboard拖線的,這個(gè)時(shí)候要選擇Custom
但是如果直接選擇Custom的話會(huì)報(bào)以下錯(cuò)誤,讓你重寫- perform方法

Snip20161101_4.png
#import <UIKit/UIKit.h>
@interface AdaptiveStoryboardSegue : UIStoryboardSegue
@end
#import "AdaptiveStoryboardSegue.h"
#import "AdaptivePresentationController.h"

@implementation AdaptiveStoryboardSegue
//如果沒有實(shí)現(xiàn)transitioningDelegate 此時(shí)不會(huì)報(bào)錯(cuò),但是呈現(xiàn)出來(lái)的效果跟Modal出來(lái)的一樣
- (void)perform {
    UIViewController *sourceController = self.sourceViewController;//官方的demo這里是destinationViewController,但是結(jié)果沒有影響
    UIViewController *desitinationController = self.destinationViewController;
    
    AdaptivePresentationController *presentationViewController = [[AdaptivePresentationController alloc]initWithPresentedViewController:desitinationController presentingViewController:sourceController];
    desitinationController.transitioningDelegate = presentationViewController;
    [sourceController presentViewController:desitinationController animated:YES completion:nil];
}
@end

其他的跟上一篇自定義轉(zhuǎn)場(chǎng)動(dòng)畫的套路是一樣的,主要的代碼還是在UIViewControllerAnimatedTransitioning里面,在源碼里面我寫了很多注釋,就不一一在這里說(shuō)明了。
說(shuō)個(gè)小技巧,可以看出我在secondViewController寫的是

 [self performSegueWithIdentifier:@"backtoFirstViewController" sender:sender];

但是可以在storyboard里面并沒有看到有Segue的連線,只有跳轉(zhuǎn)到secondViewController的連線,那么是怎么讓它跳轉(zhuǎn)回去的呢?
![1.jpeg](http://upload-images.jianshu.io/upload_images/1851080-1ba0974e248c6ae7.jpeg?
![Uploading Snip20161103_6_731627.png . . .]
imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
點(diǎn)擊secondViewController,我們可以看到這樣

Snip20161103_6.png

有一根Segue并且有一個(gè)identifieraction,那么這個(gè)事件是怎么回事的呢?原來(lái)這個(gè)事件是寫在源控制器里的

//這個(gè)方法并不是隨便添加的,而是為了在secondViewController的Exit連接事件的時(shí)候有這個(gè)action,就可以返回到當(dāng)前的控制器
- (IBAction)backtoFirstViewController:(UIStoryboardSegue *)sender{
    
}

然后點(diǎn)擊secondViewControllerExit就可以看到這樣方法,把這個(gè)方法連線到secondViewController上就可以了。

Snip20161103_7.png
第二種動(dòng)畫(Checkboard)

第二個(gè)動(dòng)畫思路是:在containerView上面有一層黑色的view,按照某一個(gè)固定的尺寸切割等分,然后雙層嵌套循環(huán)創(chuàng)建很多個(gè)view添加到當(dāng)前的黑色的view 。然后計(jì)算出哪些view將要3D旋轉(zhuǎn)。
可以看出是對(duì)系統(tǒng)本身的UINavigationController的動(dòng)畫做了自定義
查了一些資料,navigation controller有一個(gè)方法,代理來(lái)檢索有沒有animator objec對(duì)象來(lái)作用在傳入的試圖控制器上,如果這個(gè)方法實(shí)現(xiàn)了,將返回一個(gè)遵守了UIViewControllerAnimatedTransitioning協(xié)議的對(duì)象 如果沒有的話就默認(rèn)是push或者pop動(dòng)畫,這個(gè)方法就是

- (nullable id <UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
                                            animationControllerForOperation:(UINavigationControllerOperation)operation
                                                         fromViewController:(UIViewController *)fromVC
                                                           toViewController:(UIViewController *)toVC{
    
}

返回的是一個(gè)遵守UIViewControllerAnimatedTransitioning協(xié)議的對(duì)象,主要的代碼還是在這里面,但是有一段代碼看的我整個(gè)人都不好了,求 大神指教

 //計(jì)算當(dāng)前正在飛行的片數(shù)  從這里開始整個(gè)人懵逼了 看不懂
    __block NSUInteger sliceAnimationsPending = 0;
    for (NSInteger y = 0; y <verticalSlices; y ++) {
        for (NSInteger x = 0; x < horizontalSlices; x ++) {
           
            UIView *toCheckboardView = transitionContainer.subviews[y * horizontalSlices * 2 + (x * 2)];
            UIView *fromCheckboardView = transitionContainer.subviews[y * horizontalSlices * 2 + (x * 2 + 1)];
            CGVector sliceOriginVector;
            if (isPush) {
                sliceOriginVector = CGVectorMake(CGRectGetMinX(fromCheckboardView.frame) - CGRectGetMinX(transitionContainer.bounds),
                                                 CGRectGetMinY(fromCheckboardView.frame) - CGRectGetMinY(transitionContainer.bounds));
            }else{
                sliceOriginVector = CGVectorMake(CGRectGetMaxX(fromCheckboardView.frame) - CGRectGetMaxX(transitionContainer.bounds),
                                                 CGRectGetMaxY(fromCheckboardView.frame) - CGRectGetMaxY(transitionContainer.bounds));
            }
            
            CGFloat dot = sliceOriginVector.dx * transitionVector.dx + sliceOriginVector.dy * transitionVector.dy;
            CGVector projection = CGVectorMake(transitionUnitVector.dx * dot/transitionVectorLength,
                                               transitionUnitVector.dy * dot/transitionVectorLength);
            
            CGFloat projectionLength = sqrtf( projection.dx * projection.dx + projection.dy * projection.dy );
            
            NSTimeInterval startTime = projectionLength/(transitionVectorLength + transitionSpacing) * transitionDuration;
            NSTimeInterval duration = ( (projectionLength + transitionSpacing)/(transitionVectorLength + transitionSpacing) * transitionDuration ) - startTime;
            
            sliceAnimationsPending++;
            
            [UIView animateWithDuration:duration delay:startTime options:0 animations:^{
                toCheckboardView.layer.transform = CATransform3DIdentity;
                fromCheckboardView.layer.transform = CATransform3DMakeRotation(M_PI, 0, 1, 0);
            } completion:^(BOOL finished) {
            
                if (--sliceAnimationsPending == 0) {
                    BOOL wasCancelled = [transitionContext transitionWasCancelled];
                    [transitionContainer removeFromSuperview];
                    [transitionContext completeTransition:!wasCancelled];
                }
            }];

        }
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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