瞎搞iOS轉(zhuǎn)場(chǎng)(-)

想寫(xiě)簡(jiǎn)書(shū)很久了 一直沒(méi)時(shí)間 剛好項(xiàng)目做完了 現(xiàn)在來(lái)寫(xiě)篇簡(jiǎn)書(shū)吧 有很多不足之處希望大家多多指正批評(píng) 好 下面進(jìn)入正題
先上效果圖

pushTransition.gif

這其實(shí)一個(gè)自定義push轉(zhuǎn)場(chǎng)動(dòng)畫(huà) 關(guān)于轉(zhuǎn)場(chǎng)動(dòng)畫(huà) 網(wǎng)上資料也很多 我現(xiàn)在貼出一篇我覺(jué)得寫(xiě)的很好的傳送門(mén)

分析動(dòng)畫(huà)

先要了解幾個(gè)概念 from 和 to 在代碼中經(jīng)常看到fromView和toView這類(lèi)的
1.fromView表示當(dāng)前視圖
2.toView表示要跳轉(zhuǎn)到的視圖
我們似乎可以看到是fromView旋轉(zhuǎn)了180° 其實(shí)不是這樣的 我是這樣處理的 先讓toView旋轉(zhuǎn)90° 然后此時(shí)fromView和頭view形成了一個(gè)+形狀 然后讓fromView旋轉(zhuǎn)90° 完成后 toView在旋轉(zhuǎn)90° 這樣就達(dá)到這個(gè)動(dòng)畫(huà) 當(dāng)然要注意旋轉(zhuǎn)的方向 這些在代碼中有詳細(xì)的注釋

定義轉(zhuǎn)場(chǎng)動(dòng)畫(huà)

首先定義一個(gè)遵循了UIViewControllerAnimatedTransitioning協(xié)議的類(lèi)。并且實(shí)現(xiàn)下面2個(gè)方法

- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext ;

- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext;

第一個(gè)方法是返回轉(zhuǎn)場(chǎng)的時(shí)間 第二個(gè)方法可以拿到轉(zhuǎn)場(chǎng)的上下文(上下文大家很明白吧)這個(gè)上下文里面就包含我們轉(zhuǎn)場(chǎng)需要的幾乎所有元素 包括fromView fromVC toView 等等 然后我們這里寫(xiě)我們的動(dòng)畫(huà)的邏輯就可以了
需要注意的一點(diǎn)就是 我們要把push 和 pop的動(dòng)畫(huà)分開(kāi) 所以我是這樣處理的

- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext{
    switch (self.type) {
        case XWPushTransitionManagerPush:
            [self doPushAnimation:transitionContext];
            break;
        case XWPushTransitionManagerPop:
            [self doPopAnimation:transitionContext];
            break;
        default:
            break;
    }
}

最后貼出我動(dòng)畫(huà)的邏輯

- (void)ThrerDPushAnimation:(id<UIViewControllerContextTransitioning>)transitionContext{
    
    // 將要轉(zhuǎn)場(chǎng)出來(lái)的view
    UIView *toView =[transitionContext viewForKey:UITransitionContextToViewKey];
    // 當(dāng)前的view
    UIView *formView = [transitionContext viewForKey:UITransitionContextFromViewKey];
    // 轉(zhuǎn)場(chǎng)的容器
    UIView *contaniView = [transitionContext containerView];
    contaniView.backgroundColor = [UIColor orangeColor];
    CATransform3D percatier = CATransform3DIdentity;
    // 設(shè)置m34 才有立體效果
    percatier.m34 = -1.0/500;
    //sublayerTranform
    // 設(shè)置了父視圖的sublayerTranform 子視圖就都有這個(gè)transform
    contaniView.layer.sublayerTransform = percatier;
    [contaniView  addSubview:toView];
    [contaniView  addSubview:formView];
    
    //toview 默認(rèn)旋轉(zhuǎn)90
    CATransform3D tranform1 = CATransform3DMakeRotation(-M_PI_2,0,1,0);
    toView.layer.transform = tranform1;
    
    
    // formview 的旋轉(zhuǎn)角度 也是90  當(dāng)formview旋轉(zhuǎn)到90度時(shí)候 移除formview  并且toview開(kāi)始動(dòng)畫(huà)
    // 其實(shí)2個(gè)view 各自只旋轉(zhuǎn)了90度
    CATransform3D tranform2 = CATransform3DMakeRotation(M_PI_2,0,1,0);
    
    // 關(guān)鍵幀動(dòng)畫(huà)
    // StartTime:動(dòng)畫(huà)開(kāi)始時(shí)間         取值0-1 指的是比例
    // relativeDuration: 動(dòng)畫(huà)持續(xù)時(shí)間 取值0-1 指的是比例
    [UIView animateKeyframesWithDuration:Time delay:0 options:UIViewKeyframeAnimationOptionCalculationModeLinear animations:^{
        [UIView addKeyframeWithRelativeStartTime:0 relativeDuration:0.5 animations:^{
            // 當(dāng)前的view 旋轉(zhuǎn)90度
            formView.layer.transform = tranform2;
        }];
        
        // formview 動(dòng)畫(huà)完成后 toView 進(jìn)行動(dòng)畫(huà)
        [UIView addKeyframeWithRelativeStartTime:0.5 relativeDuration:0.5 animations:^{
            toView.layer.transform = CATransform3DIdentity;
        }];
    } completion:^(BOOL finished) {
         // 動(dòng)畫(huà)完成之后 要告訴系統(tǒng) 轉(zhuǎn)場(chǎng)完成了 不然會(huì)出現(xiàn)bug
        [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
        [formView removeFromSuperview];
    }];
}

最后我們?cè)O(shè)置轉(zhuǎn)場(chǎng)的代理并且設(shè)置UINavigationControllerDelegate 在代理方法中返回我們定義的類(lèi)

#pragma mark -- 代理
- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC{
    //分pop和push兩種情況分別返回動(dòng)畫(huà)過(guò)渡代理相應(yīng)不同的動(dòng)畫(huà)操作
    return [XWPushTransitionManager transitionWithType:operation == UINavigationControllerOperationPush ? XWPushTransitionManagerPush : XWPushTransitionManagerPop];
}

這里的UINavigationControllerOperation 這個(gè)枚舉就是來(lái)區(qū)分是push 還是 pop 我們只需要返回對(duì)應(yīng)的就可以拉
至此 我們的瞎搞push轉(zhuǎn)場(chǎng)就完成了 當(dāng)然你還得實(shí)現(xiàn)pop 這很簡(jiǎn)單 就動(dòng)畫(huà)的反向

手勢(shì)驅(qū)動(dòng)

最后我們?cè)诩由弦粋€(gè)效果 就是手勢(shì)驅(qū)動(dòng) 啥事手勢(shì)驅(qū)動(dòng)呢 系統(tǒng)默認(rèn)的 Push 和 Pop 動(dòng)畫(huà)都支持手勢(shì)驅(qū)動(dòng) 并且可以根據(jù)手勢(shì)移動(dòng)距離改變動(dòng)畫(huà)完成度 在iOS7以后 蘋(píng)果為我們提供了一個(gè)UIPercentDrivenInteractiveTransition這個(gè)類(lèi) 這個(gè)類(lèi)就是專門(mén)來(lái)做手勢(shì)驅(qū)動(dòng)的 廢話不多說(shuō) 下面直接開(kāi)搞
1.自定義一個(gè)類(lèi) 繼承于UIPercentDrivenInteractiveTransition 重寫(xiě)初始化方法 傳入一個(gè)控制器(一般是push出來(lái)的vc)
2.個(gè)該vc添加一個(gè)Pan手勢(shì)
3.在手勢(shì)的監(jiān)聽(tīng)方法里面計(jì)算手勢(shì)移動(dòng)的百分比 并使用 UIPercentDrivenInteractiveTransition 屬性的 updateInteractiveTransition 方法實(shí)時(shí)更新百分比
4.最后實(shí)現(xiàn)UINavigationControllerDelegate的一個(gè)代理方法

- (nullable id <UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController
                                   interactionControllerForAnimationController:(id <UIViewControllerAnimatedTransitioning>) animationController NS_AVAILABLE_IOS(7_0){
    // 這里要判斷 是pop返回 還是手勢(shì)返回
    return self.manager.isInteractive?self.manager:nil;
}

至此 手勢(shì)驅(qū)動(dòng)也完成了啊 是不是很簡(jiǎn)單呢 其實(shí)不是 這里面水很深的 有很多細(xì)節(jié) 尤其加入了手勢(shì)驅(qū)動(dòng) pop動(dòng)畫(huà)尤其得注意了 具體的我在代碼里面注釋了 貼出demo地址demo地址
最后希望大家pi'p

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容