寫在前面
在簡(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ò)散

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


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


4、XWCoolAnimator 自定義一些效果







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








如何使用
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)在的
未解決

解決后

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ù)后


可以看見,修復(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á)到目的