幾句代碼快速集成自定義轉(zhuǎn)場(chǎng)效果+ 全手勢(shì)驅(qū)動(dòng)

寫在前面

在簡(jiǎn)書寫完第一篇的自定義轉(zhuǎn)場(chǎng)文章后,已經(jīng)很久沒有碰過(guò)轉(zhuǎn)場(chǎng)了,畢竟在公司,功能實(shí)現(xiàn)才是最重要的,這些轉(zhuǎn)場(chǎng)的動(dòng)效,只能是點(diǎn)睛之筆,不太容易被重視,不過(guò)我的第一篇文章還是很多人的喜歡和討論,很多人還提出些建議,非常感謝大家,這是我第一篇文章的地址自定義轉(zhuǎn)場(chǎng)動(dòng)畫,里面包含了一些轉(zhuǎn)場(chǎng)的基礎(chǔ)知識(shí),這篇文章我就不再討論這些基礎(chǔ)知識(shí)了。
為什么會(huì)有這第二篇文章,主要原因有如下幾點(diǎn):

1、能不能更簡(jiǎn)單?當(dāng)我很久沒有使用轉(zhuǎn)場(chǎng)的時(shí)候,再次來(lái)使用它,感覺還是比較煩瑣,有一大堆記不住的長(zhǎng)長(zhǎng)的代理方法,都要去copy,長(zhǎng)長(zhǎng)的代理方法也把控制器弄得有點(diǎn)亂,雖然蘋果已經(jīng)將整個(gè)過(guò)程充分解耦了,我在想,要是能簡(jiǎn)單的一兩句話就能集成轉(zhuǎn)場(chǎng)效果多好,或者通過(guò)繼承和復(fù)寫一兩個(gè)方法就能輕松實(shí)現(xiàn)自己的轉(zhuǎn)場(chǎng)效果,無(wú)需關(guān)注轉(zhuǎn)場(chǎng)邏輯,只需關(guān)注動(dòng)畫邏輯

2、閃爍和生硬?在第一篇文章中有人提到的部分的bug,比如小圓點(diǎn)擴(kuò)散效果,如果手勢(shì)在中途取消,不會(huì)有取消動(dòng)畫,非常生硬,而且會(huì)有閃爍的bug,我在想能不能解決這兩個(gè)問(wèn)題,強(qiáng)迫癥接受不了o(╯□╰)o,我現(xiàn)在找到了一個(gè)比較好的方式來(lái)解決問(wèn)題,原理和對(duì)比圖會(huì)在后面給出

3、能不能多添加一些效果?所以我把自己寫的效果封裝,再參照網(wǎng)絡(luò)一些效果,總過(guò)添加了將近20個(gè)效果

4、手勢(shì)萬(wàn)歲!任何效果我都想能夠手勢(shì)驅(qū)動(dòng)

效果圖(圖比較多,請(qǐng)手機(jī)用戶慎重,可下載demo真機(jī)運(yùn)行效果更好)

截圖中,右上角的switch開關(guān)代表push和present,所有效果都支持手勢(shì),我就不一一演示了

1、CircleSpreadTransition 小圓點(diǎn)擴(kuò)散

CircleSpreadTransition.gif

2、MagicMoveTransition 神奇移動(dòng)

MagicMoveTransition1.gif

MagicMoveTransition2.gif

3、XWDrawerAnimator 抽屜效果,仿照QQ和淘寶

XWDrawerAnimator1.gif

XWDrawerAnimator2.gif

4、XWCoolAnimator 自定義一些效果

XWCoolAnimator2.gif

XWCoolAnimator1.gif

XWCoolAnimator3.gif

XWCoolAnimator4.gif

XWCoolAnimator5.gif

XWCoolAnimator6.gif

XWCoolAnimator7.gif

5、XWFilterAnimator 通過(guò)CIFilter濾鏡自定義一些效果,請(qǐng)?jiān)谡鏅C(jī)上運(yùn)行

XWFilterAnimator1.gif

XWFilterAnimator6.gif

XWFilterAnimator5.gif

XWFilterAnimator4.gif

XWFilterAnimator3.gif

XWFilterAnimator2.gif

XWFilterAnimator8.gif

XWFilterAnimator7.gif

如何使用

1、git地址:幾句代碼快速集成自定義轉(zhuǎn)場(chǎng)效果+ 全手勢(shì)驅(qū)動(dòng),clone后將整個(gè)XWTranstion文件夾導(dǎo)入工程

2、導(dǎo)入UINavigationController+XWTransition.h或者UIViewController+XWTransition.h兩個(gè)分類

3、選擇你需要的效果器進(jìn)行根據(jù)初始化方法進(jìn)行初始化,比如下面的小圓點(diǎn)擴(kuò)散,初始化指定開始圓心和半徑

XWCircleSpreadAnimator *animator = [XWCircleSpreadAnimator xw_animatorWithStartCenter:self.button.center radius:20];
    

4、通過(guò)初始化的效果器轉(zhuǎn)場(chǎng),根據(jù)分類提供的方法進(jìn)行push或者present,就完成了!

[self.navigationController xw_pushViewController:toVC withAnimator:animator];
或者
[self xw_presentViewController:toVC withAnimator:animator];

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

1、在UIViewController+XWTransition.h分類中提供了兩個(gè)方法,用來(lái)注冊(cè)手勢(shì)驅(qū)動(dòng),在viewDidLoad的時(shí)候調(diào)用注冊(cè)手勢(shì)就可以了,詳見demo,注意避免循環(huán)引用,手勢(shì)支持邊緣屬性

/**
 *  注冊(cè)to手勢(shì)(push或者Present手勢(shì))
 *
 *  @param direction       手勢(shì)方向
 *  @param tansitionConfig 手勢(shì)觸發(fā)的block,block中需要包含你的push或者Present的邏輯代碼,注意避免循環(huán)引用問(wèn)題
 *  @param edgeSpacing     手勢(shì)觸發(fā)的邊緣距離,該值為0,表示在整個(gè)控制器視圖上都有效,否者這在邊緣的edgeSpacing之類有效
 */

- (void)xw_registerToInteractiveTransitionWithDirection:(XWInteractiveTransitionGestureDirection)direction transitonBlock:(dispatch_block_t)tansitionConfig edgeSpacing:(CGFloat)edgeSpacing;

/**
 *  注冊(cè)back手勢(shì)(pop或者dismiss手勢(shì))
 *
 *  @param direction       手勢(shì)方向
 *  @param tansitionConfig 手勢(shì)觸發(fā)的block,block中需要包含你的pop或者dismiss的邏輯代碼,注意避免循環(huán)引用問(wèn)題
 *  @param edgeSpacing     手勢(shì)觸發(fā)的邊緣距離,該值為0,表示在整個(gè)控制器視圖上都有效,否者這在邊緣的edgeSpacing之類有效
 */

- (void)xw_registerBackInteractiveTransitionWithDirection:(XWInteractiveTransitionGestureDirection)direction transitonBlock:(dispatch_block_t)tansitionConfig edgeSpacing:(CGFloat)edgeSpacing;

2、事例代碼

    __weak typeof(self)weakSelf = self;
    //注冊(cè)一個(gè)全屏的back轉(zhuǎn)場(chǎng)
    [self xw_registerBackInteractiveTransitionWithDirection:XWInteractiveTransitionGestureDirectionDown transitonBlock:^{
    //pop或者dismiss操作
        [weakSelf xw_transiton];
    } edgeSpacing:0];

關(guān)于神奇移動(dòng)效果

1、在UIViewController+XWTransition.h分類中提供了三個(gè)關(guān)于神奇移動(dòng)的方法,你需要在轉(zhuǎn)場(chǎng)前和轉(zhuǎn)場(chǎng)后的控制器中分別注冊(cè)神奇移動(dòng)前后的視圖(用來(lái)告知神奇移動(dòng)前后的frame),然后通過(guò)神奇移動(dòng)效果器就可以觸發(fā)神奇移動(dòng)轉(zhuǎn)場(chǎng)了

/**
 * 注冊(cè)神奇移動(dòng)起始視圖
 *
 * @param group 神奇移動(dòng)起始視圖數(shù)組
 */
- (void)xw_addMagicMoveStartViewGroup:(NSArray<UIView *> *)group;

/**
 * 注冊(cè)神奇移動(dòng)終止視圖
 *
 * @param group 神奇移動(dòng)終止視圖數(shù)組,注意起始視圖數(shù)組和終止視圖數(shù)組的視圖需要一一對(duì)應(yīng)才能有正確的效果
 */
- (void)xw_addMagicMoveEndViewGroup:(NSArray<UIView *> *)group;

/**
 * 改變神奇移動(dòng)起始視圖,因?yàn)樵赽ack的時(shí)候,有可能不需要再回到原來(lái)起始的位置,需要去一個(gè)新的視圖位置,所以在back前需要調(diào)用該方法改變起始視圖數(shù)組
 *
 * @param group 新的起始視圖數(shù)組
 */
- (void)xw_changeMagicMoveStartViewGroup:(NSArray<UIView *> *)group;

2、事例代碼

    //fromVC轉(zhuǎn)場(chǎng)前控制器中注冊(cè)神奇移動(dòng)前視圖
    [self xw_addMagicMoveStartViewGroup:@[imgView, view1, view2]];
    //toVC轉(zhuǎn)場(chǎng)后控制器中注冊(cè)神奇移動(dòng)前視圖
    [self xw_addMagicMoveEndViewGroup:@[imgView, view1, view2]];
    //初始化神奇移動(dòng)效果器轉(zhuǎn)場(chǎng)
    XWMagicMoveToController *toVC = [XWMagicMoveToController new];
    [self xw_presentViewController:toVC withAnimator:animator];
    

3、轉(zhuǎn)場(chǎng)中存在cell,由于在轉(zhuǎn)場(chǎng)過(guò)程中cell還沒有加載,所以無(wú)法注冊(cè)cell為神奇移動(dòng)視圖,這種情況需要生產(chǎn)一個(gè)零時(shí)視圖注冊(cè)為轉(zhuǎn)場(chǎng)視圖來(lái)使用,具體請(qǐng)參考demo中的九宮格例子

4、關(guān)于提供的imageMode屬性:在神奇移動(dòng)中,有個(gè)問(wèn)題,就是移動(dòng)中的臨時(shí)視圖一般都是用截圖大法截圖而來(lái)的,但是如果從從小圖變成大圖,由于截圖為小圖截圖,變大過(guò)程中會(huì)有模糊的現(xiàn)象,如果設(shè)置了該屬性,我會(huì)對(duì)神奇移動(dòng)視圖中的包含了image的視圖進(jìn)行檢測(cè),如果能檢測(cè)到image則直接取image,而不截圖,就能解決模糊的問(wèn)題,代碼如下

- (UIView *)_xw_snapshotView:(UIView *)view{
    CALayer *layer = view.layer;
    UIView *snapView = [UIView new];
    snapView.frame = view.frame;
    BOOL imgMode = [objc_getAssociatedObject(view, &kXWMagicMovePropertyInViewKey) boolValue] || _imageMode;
    UIImage *img = nil;
    if (imgMode) {//如果開啟imgMode,優(yōu)先直接獲取圖片,避免截圖時(shí)時(shí)從小到大造成的模糊
        if ([view isKindOfClass:[UIImageView class]]) {//取imageView中的image
            img = [(UIImageView *)view image];
        }else if ([view isKindOfClass:[UIButton class]]){//取button中的image
            img = [(UIButton *)view currentImage];
        }
        if (!img && [view isKindOfClass:[UIView class]]) {//沒取到嘗試取content
            img = [UIImage imageWithCGImage:(__bridge CGImageRef)view.layer.contents];
        }
    }
    //若都沒有取到,則截圖
    if (!img) {
        UIGraphicsBeginImageContextWithOptions(layer.bounds.size, layer.opaque, 0);
        CGContextRef context = UIGraphicsGetCurrentContext();
        [layer renderInContext:context];
        img = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
    }
    snapView.layer.contents = (__bridge id)img.CGImage;
    return snapView;
}

關(guān)于抽屜效果的全屏拖動(dòng)

1、抽屜效果由于注冊(cè)的手勢(shì)都是在控制器的的視圖上,如果做QQ設(shè)置界面的效果,不可能在toVC之外點(diǎn)擊和拖動(dòng)能夠back,我的思路是會(huì)在toVC沒有覆蓋的區(qū)域添加一個(gè)透明視圖,給透明視圖加上點(diǎn)擊和拖動(dòng)手勢(shì),具體代碼如下


//首先需要設(shè)置點(diǎn)擊和拖動(dòng)的back操作,block中應(yīng)該包含你的dismiss或者pop邏輯
/**
 *  開啟邊緣(就是屏幕除開toView所占用的部分)back手勢(shì)和邊緣點(diǎn)擊返回效果,類似于QQ設(shè)置界面的返回效果
 *
 *  @param backConfig 返回操作,您的dismiss或者pop操作
 */
- (void)xw_enableEdgeGestureAndBackTapWithConfig:(dispatch_block_t)backConfig;


//添加全屏手勢(shì)代碼如下
/**
 *  添加全局手勢(shì)和點(diǎn)擊視圖
 */
- (void)_xw_addFullGestureAndTapBackViewInContainerView:(UIView *)containerView toView:(UIView *)toView distance:(CGFloat)distance{
    CGFloat width = _vertical ? containerView.frame.size.width : containerView.frame.size.width - fabs(distance);
    CGFloat height = _vertical ? containerView.frame.size.height - fabs(distance) : containerView.frame.size.height;
    //如果toVC是全屏鋪滿則無(wú)需添加全局手勢(shì),直接使用toVC的view的手勢(shì)就好了
    if (width == 0 || height == 0)return;
    if (!_backConfig) return;
    //如果toView注冊(cè)過(guò)手勢(shì),我們直接獲取這個(gè)手勢(shì)
    NSArray<UIGestureRecognizer *> *gestures = toView.gestureRecognizers;
    __block id target = nil;
    [gestures enumerateObjectsUsingBlock:^(UIGestureRecognizer * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        NSString *panType = objc_getAssociatedObject(obj, "xw_interactivePanKey");
        if ([panType isEqualToString:@"xw_interactiveBackPan"] && obj.delegate) {
            target = obj.delegate;
            *stop = YES;
        }
    }];
    CGFloat x = _vertical || _direction == XWDrawerAnimatorDirectionRight ? 0 : -distance;
    CGFloat y = !_vertical || _direction == XWDrawerAnimatorDirectionBottom ? 0 : -distance;
    UIControl *gestureView = [UIControl new];
    //添加點(diǎn)擊事件
    [gestureView addTarget:self action:@selector(_xw_backConfig) forControlEvents:UIControlEventTouchUpInside];
    gestureView.frame = CGRectMake(x, y, width, height);
    gestureView.backgroundColor = [UIColor clearColor];
    //第一種情況,toView已經(jīng)添加了返回手勢(shì),我們直接拿到該手勢(shì)的target和action
    if (target) {
        //給containerView添加全局手勢(shì)
        UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:target action:NSSelectorFromString(@"_xw_handleGesture:")];
        [containerView addGestureRecognizer:pan];
        
    }else{
        //第二種情況,toView沒有添加手勢(shì),我們需要?jiǎng)?chuàng)建一個(gè)
        __weak typeof(self)weakSelf = self;
        XWInteractiveTransition *backTransition = [XWInteractiveTransition xw_interactiveTransitionWithDirection:(XWInteractiveTransitionGestureDirection)_direction config:^{
            weakSelf.backConfig();
        } edgeSpacing:0];
        backTransition.panRatioBaseValue = _vertical ? containerView.frame.size.height : containerView.frame.size.width;
        [backTransition xw_addPanGestureForView:gestureView to:NO];
//        [self xw_setBackInteractiveTransition:backTransition];
        [self setValue:backTransition forKey:@"backTransition"];
    }
    [containerView addSubview:gestureView];
}

解決動(dòng)畫生硬

1、先看小圓點(diǎn)效果的例子,前面是解決前寫的,后面是現(xiàn)在的

未解決


小圓點(diǎn)未開啟timer.gif

解決后

小圓開啟timer.gif

2、問(wèn)題原因:在手勢(shì)結(jié)束后該效果不會(huì)動(dòng)畫的過(guò)渡到成功或者失敗,而是整個(gè)轉(zhuǎn)場(chǎng)進(jìn)度會(huì)直接update到0或者1,就木有動(dòng)畫了

3、解決:在手指松開的時(shí)候,我會(huì)開啟一個(gè)CADisplayLink來(lái)不斷的刷新整個(gè)轉(zhuǎn)場(chǎng)進(jìn)度到1或者0,來(lái)達(dá)到動(dòng)畫的效果,具體代碼如下

case UIGestureRecognizerStateEnded:{//轉(zhuǎn)場(chǎng)結(jié)束后
            //判斷是否需要timer
            if (!_timerEable) {
                _percent >= 0.5 ? [self _xw_finish] : [self _xw_cancle];
                return;
            }
            //判斷此時(shí)是否已經(jīng)轉(zhuǎn)場(chǎng)完成,大于1或者小于0
            BOOL canEnd = [self _xw_canEndInteractiveTransitionWithPercent:_percent];
            if (canEnd) return;
            //開啟timer
            [self _xw_setEndAnimationTimerWithPercent:_percent];
            
            
//設(shè)置開啟timer
- (void)_xw_setEndAnimationTimerWithPercent:(CGFloat)percent{
    _percent = percent;
    //根據(jù)失敗還是成功設(shè)置刷新間隔
    if (percent > 0.5) {
        _timeDis = (1 - percent) / ((1 - percent) * 60);
    }else{
        _timeDis = percent / (percent * 60);
    }
    //開啟timer
    [self _xw_startTimer];
}
//開啟timer
- (void)_xw_startTimer{
    if (_timer) {
        return;
    }
    _timer = [CADisplayLink displayLinkWithTarget:self selector:@selector(_xw_timerEvent)];
    [_timer addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
}

//timer 事件
- (void)_xw_timerEvent{
    if (_percent > 0.5) {
        _percent += _timeDis;
    }else{
        _percent -= _timeDis;
    }
    //通過(guò)timer不斷刷新轉(zhuǎn)場(chǎng)進(jìn)度,達(dá)到動(dòng)畫效果
    [self _xw_updatingWithPercent:_percent];
    //判斷進(jìn)度是否達(dá)到0和1,達(dá)到則結(jié)束timer,結(jié)束轉(zhuǎn)場(chǎng)
    BOOL canEnd = [self _xw_canEndInteractiveTransitionWithPercent:_percent];
    if (canEnd) {
        [self _xw_stopTimer];
    }
}

解決閃爍問(wèn)題

1、閃爍原因:在不使用UIView的動(dòng)畫block時(shí),我們直接為layer添加一個(gè)CAAnimtion,此時(shí)會(huì)先設(shè)置modelLayer為轉(zhuǎn)場(chǎng)成功的狀態(tài),比如小圓點(diǎn)效果會(huì)設(shè)置path為大圓的path,但是如果轉(zhuǎn)場(chǎng)失敗,presentLayer依然會(huì)先變?yōu)閙odelLayer設(shè)置的成功值,然后動(dòng)畫才結(jié)束,走我們的轉(zhuǎn)場(chǎng)失敗邏輯,所以就會(huì)閃爍

2、解決:我把手勢(shì)改變的一些關(guān)鍵狀態(tài)通過(guò)代理傳出來(lái),在手勢(shì)結(jié)束前,我們?nèi)绻麢z查到失敗,可以先將modelLayer的值標(biāo)記為失敗時(shí)候的值,也就是初始值,就解決了該問(wèn)題

3、事例代碼

//手勢(shì)轉(zhuǎn)場(chǎng)時(shí)的代理事件,animator默認(rèn)為為其手勢(shì)的代理,復(fù)寫對(duì)應(yīng)的代理事件可處理一些手勢(shì)失敗閃爍的情況
@protocol XWInteractiveTransitionDelegate <NSObject>

@optional
/**手勢(shì)轉(zhuǎn)場(chǎng)即將開始時(shí)調(diào)用*/
- (void)xw_interactiveTransitionWillBegin:(XWInteractiveTransition *)interactiveTransition;
/**手勢(shì)轉(zhuǎn)場(chǎng)中調(diào)用*/
- (void)xw_interactiveTransition:(XWInteractiveTransition *)interactiveTransition isUpdating:(CGFloat)percent;
/**如果開始了轉(zhuǎn)場(chǎng)手勢(shì)timer,會(huì)在松開手指,timer開始的時(shí)候調(diào)用*/
- (void)xw_interactiveTransitionWillBeginTimerAnimation:(XWInteractiveTransition *)interactiveTransition;
/**手勢(shì)轉(zhuǎn)場(chǎng)結(jié)束的時(shí)候調(diào)用*/
- (void)xw_interactiveTransition:(XWInteractiveTransition *)interactiveTransition willEndWithSuccessFlag:(BOOL)flag percent:(CGFloat)percent;

@end

//我在小圓點(diǎn)擴(kuò)散效果中處理的如下
- (void)xw_interactiveTransition:(XWInteractiveTransition *)interactiveTransition willEndWithSuccessFlag:(BOOL)flag percent:(CGFloat)percent{
    if (!flag) {
        //防止失敗后的閃爍,如果失敗將遮罩的path設(shè)置為其實(shí)的小圓path
        _maskLayer.path = _startPath.CGPath;
    }
    _containerView.userInteractionEnabled = YES;
}

關(guān)于coolTransiton

1、直接通過(guò)枚舉初始化就有已經(jīng)集成的部分效果,具體如下:

typedef NS_ENUM(NSUInteger, XWCoolTransitionAnimatorType){
    //全屏翻頁(yè)
    XWCoolTransitionAnimatorTypePageFlip,
    //中間翻頁(yè)
    XWCoolTransitionAnimatorTypePageMiddleFlipFromLeft,
    XWCoolTransitionAnimatorTypePageMiddleFlipFromRight,
    XWCoolTransitionAnimatorTypePageMiddleFlipFromTop,
    XWCoolTransitionAnimatorTypePageMiddleFlipFromBottom,
    //開窗
    XWCoolTransitionAnimatorTypePortal,
    //折疊
    XWCoolTransitionAnimatorTypeFoldFromLeft,
    XWCoolTransitionAnimatorTypeFoldFromRight,
    //爆炸
    XWCoolTransitionAnimatorTypeExplode,
    //酷炫線條效果
    XWCoolTransitionAnimatorTypeHorizontalLines,
    XWCoolTransitionAnimatorTypeVerticalLines,
    //掃描效果
    XWCoolTransitionAnimatorTypeScanningFromLeft,
    XWCoolTransitionAnimatorTypeScanningFromRight,
    XWCoolTransitionAnimatorTypeScanningFromTop,
    XWCoolTransitionAnimatorTypeScanningFromBottom,
};

2、 cool轉(zhuǎn)場(chǎng)效果中的Portal、Fold、Explode效果的部分代碼邏輯來(lái)源于ColinEberhardt/VCTransitionsLibrary,非常感謝作者,我只是將其進(jìn)行了部分改動(dòng),以便對(duì)手勢(shì)的支持更加完善,里面還有許多其他效果,本人經(jīng)歷有限就沒有再集成進(jìn)來(lái)了,大家可以自行查看;cool轉(zhuǎn)場(chǎng)效果的Lines的想法來(lái)自于cinkster/HUAnimator, 非常感謝作者,但是由于作者在對(duì)toVC截圖采用了延遲的方式來(lái)處理,導(dǎo)致了不好處理的bug和一些手勢(shì)上的bug,對(duì)此我采用了另一種方式來(lái)解決截圖的問(wèn)題,使用了layer的contentRect屬性,解決了發(fā)現(xiàn)的問(wèn)題,相關(guān)代碼請(qǐng)自行查看

關(guān)于FilterTransition

1、XWFilterAnimator 全都是基于不同的CIFilter產(chǎn)生的一些濾鏡效果,貌似在模擬器無(wú)法運(yùn)行這些效果,請(qǐng)?jiān)谡鏅C(jī)上測(cè)試,直接通過(guò)枚舉初始化就有已經(jīng)集成的部分效果,具體如下:

typedef NS_ENUM(NSUInteger, XWFilterAnimatorType) {
    XWFilterAnimatorTypeBoxBlur,//模糊轉(zhuǎn)場(chǎng),對(duì)應(yīng)CIBoxBlur
    XWFilterAnimatorTypeSwipe,//滑動(dòng)過(guò)渡轉(zhuǎn)場(chǎng),對(duì)應(yīng)CISwipeTranstion
    XWFilterAnimatorTypeBarSwipe,//對(duì)應(yīng)CIBarSwipeTranstion
    XWFilterAnimatorTypeMask,//按指定遮罩圖片轉(zhuǎn)場(chǎng),對(duì)應(yīng)CIDisintegrateWithMaskTransition
    XWFilterAnimatorTypeFlash,//閃爍轉(zhuǎn)場(chǎng),對(duì)應(yīng)CIFlashTransition
    XWFilterAnimatorTypeMod,//條紋轉(zhuǎn)場(chǎng) 對(duì)應(yīng)CIModTransition
    XWFilterAnimatorTypePageCurl,//翻頁(yè)轉(zhuǎn)場(chǎng) 對(duì)應(yīng)CIPageCurlWithShadowTransition
    XWFilterAnimatorTypeRipple,//波紋轉(zhuǎn)場(chǎng),對(duì)應(yīng)CIRippleTransition
    XWFilterAnimatorTypeCopyMachine, //效果和XWCoolAnimator中的Scanning效果類似,對(duì)應(yīng)CICopyMachineTransition
};

2、如果想要添加其他濾鏡轉(zhuǎn)場(chǎng),可以嘗試我的FilterTransition中書寫分類的方式,只需要指定CIFilter和相關(guān)邏輯即可

關(guān)于自定義轉(zhuǎn)場(chǎng)效果

1、你只需要繼承于XWTransitionAnimator,就像我上面所有的效果器一樣,然后復(fù)寫需要的屬性和兩個(gè)必須的方法即可,然后你就可以使用你自定義的效果器轉(zhuǎn)場(chǎng),XWTransitionAnimator頭文件如下:

@interface XWTransitionAnimator : NSObject<UIViewControllerTransitioningDelegate, UINavigationControllerDelegate, UITabBarControllerDelegate, XWInteractiveTransitionDelegate>

//to轉(zhuǎn)場(chǎng)時(shí)間 默認(rèn)0.5
@property (nonatomic, assign) NSTimeInterval toDuration;
//back轉(zhuǎn)場(chǎng)時(shí)間 默認(rèn)0.5
@property (nonatomic, assign) NSTimeInterval backDuration;
//是否需要開啟手勢(shì)timer,某些轉(zhuǎn)場(chǎng)如果在轉(zhuǎn)成過(guò)程中所開手指,不會(huì)有動(dòng)畫過(guò)渡,顯得很生硬,開啟timer后,松開手指,會(huì)用timer不斷的刷新轉(zhuǎn)場(chǎng)百分比,消除生硬的缺點(diǎn)
@property (nonatomic, assign) BOOL needInteractiveTimer;

/**
 *  配置To過(guò)程動(dòng)畫(push, present),自定義轉(zhuǎn)場(chǎng)動(dòng)畫應(yīng)該復(fù)寫該方法
 */
- (void)xw_setToAnimation:(id<UIViewControllerContextTransitioning>)transitionContext;
/**
 *  配置back過(guò)程動(dòng)畫(pop, dismiss),自定義轉(zhuǎn)場(chǎng)動(dòng)畫應(yīng)該復(fù)寫該方法
 */
- (void)xw_setBackAnimation:(id<UIViewControllerContextTransitioning>)transitionContext;

@end

2、這樣就只需要關(guān)心動(dòng)畫的邏輯,其余的事情就不用管了,不過(guò)如果遇到閃爍問(wèn)題,你只需要復(fù)寫相關(guān)的手勢(shì)代理方法,就像我在小圓點(diǎn)轉(zhuǎn)場(chǎng)中一樣,因?yàn)?code>XWTransitionAnimator默認(rèn)是手勢(shì)管理者的代理,所以直接實(shí)現(xiàn)代理方法就好了

寫在最后

陸陸續(xù)續(xù)的就這些了,東西比較多,可能我的敘述也還有一定問(wèn)題,某些內(nèi)容可能描述的不太清楚,請(qǐng)大家多多參考demo,希望本文能讓大家以后再設(shè)計(jì)到自定義轉(zhuǎn)場(chǎng)的時(shí)候能夠迅速解決問(wèn)題,再次復(fù)習(xí)一下地址幾句代碼快速集成自定義轉(zhuǎn)場(chǎng)效果+ 全手勢(shì)驅(qū)動(dòng) ,如果對(duì)您有幫助歡迎給予star支持!

更新 2016-06-24

今天早上思考了一下,優(yōu)化了一下DrawerAnimator,之前的toVC的frame不會(huì)隨著設(shè)置的distance改變,默認(rèn)一般都是屏幕的寬和高,也就是說(shuō)顯示之后,toVC的有一部分實(shí)際是在屏幕外面的,這對(duì)于后續(xù)的布局是不太方便的,所以我修改了一下,現(xiàn)在toVC的frame是和設(shè)置的distance相關(guān)的,所看見的toVC的部分就是toVC的全部

更新 2016-07-05

1、今天發(fā)現(xiàn)了一個(gè)問(wèn)題,就是在進(jìn)行不同的效果多次push的時(shí)候,在pop的時(shí)候,之前的效果會(huì)失效,我修復(fù)了這個(gè)問(wèn)題,請(qǐng)看截圖,上面是修復(fù)前,下面是修復(fù)后

修正之前.gif
修正之后.gif

可以看見,修復(fù)前,在最后一次back的時(shí)候,那個(gè)爆炸的效果已經(jīng)失效了,
2、問(wèn)題原因:在每次push時(shí)我會(huì)切換navigationController的delegate為當(dāng)前效果器,從而能完成轉(zhuǎn)場(chǎng)效果的邏輯,所以多次push后,代理始終是最后一個(gè)效果器,而在pop的時(shí)候那個(gè)效果器隨著對(duì)應(yīng)的pop操作已經(jīng)被銷毀了,而代理并沒有切換為之前的爆炸效果器,所以自定義轉(zhuǎn)場(chǎng)就無(wú)法觸發(fā)了
3、解決:由于我每一個(gè)效果器是和被push出的VC綁定的,所以當(dāng)被pushVC被銷毀的時(shí)候,效果器就會(huì)銷毀,此刻,應(yīng)該去檢測(cè)一下代理,如果上一個(gè)VC存在效果器,則需要切換回該效果器,所以需要在pushVC的dealloc方法中需要對(duì)代理進(jìn)行檢測(cè)和切換,為了達(dá)到目的,需要對(duì)VC的dealloc方法進(jìn)行調(diào)劑,調(diào)劑的方法稍微有點(diǎn)復(fù)雜,具體請(qǐng)看我另一篇簡(jiǎn)書文章:一句代碼,更加優(yōu)雅的調(diào)用KVO和通知中關(guān)于調(diào)劑dealloc方法的相關(guān)代碼,在dealloc中添加了代理檢測(cè)和切換的方法來(lái)達(dá)到目的

最后編輯于
?著作權(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)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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