閑來無事,整點(diǎn)活兒干干!
不整別的,先來巴拉巴拉這玩意兒怎么玩兒。
開局一張圖,內(nèi)容全靠騙

開整
首先需要滑動(dòng),那肯定得要來一個(gè)滑動(dòng)的手勢(shì),既然滑動(dòng)手勢(shì)有了,加哪?既然手勢(shì)作為全局生效,那肯定不能加在單個(gè)的view上,所以直接加在window上,這樣不就都有了嘛。
UIScreenEdgePanGestureRecognizer *gesture = [[UIScreenEdgePanGestureRecognizer alloc] initWithTarget:self action:**@selector(screenEdgePanGestureExcuteEvent:)];
gesture.edges = UIRectEdgeRight;
[Gesture_KeyWindow addGestureRecognizer:gesture];
既然手勢(shì)加上了,那不得來個(gè)響應(yīng)事件。
如何去實(shí)現(xiàn)呢,拖動(dòng)的時(shí)候要像臉上的痘痘一樣,冒出個(gè)頭,直接加個(gè)view,然后做動(dòng)畫??,你來,我整不動(dòng),別問我為什么,問就是我這么干過,結(jié)果把路走死了。
那就想想其他辦法,那不得有個(gè)玩意兒叫layer嘛。那我添加個(gè)畫布多刺激,想加啥就加啥。
說干就干。
第一步:
既然要拖,那就得先拿到位置,對(duì)吧,這個(gè)沒啥問題吧(有問題的,請(qǐng)?zhí)岢瞿愕膯栴},我不回答,我怕我打死你)。
CGPoint changePoint = [gesture locationInView:Gesture_KeyWindow];
先忽略細(xì)節(jié),開始畫豬,咱得先畫個(gè)豬腦袋吧,至少知道你畫的是個(gè)啥玩意兒,先整個(gè)效果都!
點(diǎn)拿到了,那就要開始拖了。那我們是不是得要知道兩個(gè)狀態(tài)啊,我到底是剛摁下去呢,還是在拖動(dòng),對(duì)吧,所以就有倆貨,UIGestureRecognizerStateBegan、UIGestureRecognizerStateChanged,一個(gè)是咱剛摁下去的狀態(tài),一個(gè)是在滑的狀態(tài),好了,這兩個(gè)狀態(tài)知道了,在UIGestureRecognizerStateBegan狀態(tài)是記錄開始的點(diǎn),在UIGestureRecognizerStateChanged狀態(tài)的時(shí)候記錄變化點(diǎn)。
開始動(dòng)用你的腦瓜子YY一下,咱拖的時(shí)候不是有一個(gè)痘痘一樣凸起的東西嗎?那咱先畫那個(gè)玩意兒。想想那個(gè)S一樣的曲線,腦瓜一熱,這不就來了嗎,UIBezierPath這貨,只要你牛逼,啥畫不出來,看看它的方法
- (void)moveToPoint:(CGPoint)point;
- (void)addLineToPoint:(CGPoint)point;
- (void)addCurveToPoint:(CGPoint)endPoint controlPoint1:(CGPoint)controlPoint1 controlPoint2:(CGPoint)controlPoint2;
- (void)addQuadCurveToPoint:(CGPoint)endPoint controlPoint:(CGPoint)controlPoint;
- (void)addArcWithCenter:(CGPoint)center radius:(CGFloat)radius startAngle:(CGFloat)startAngle endAngle:(CGFloat)endAngle clockwise:(BOOL)clockwiseAPI_AVAILABLE(ios(4.0));
- (void)closePath;
第一個(gè)移到一個(gè)點(diǎn),這不難理解,既然要畫那不得知道從那開始,對(duì)吧!
第二個(gè)添加一條線,還是直的,想想那個(gè)曲線,明明是彎的好吧,所以pass掉
第三個(gè)畫的是彎的線,大致就是本來是直的線段,現(xiàn)在來了倆點(diǎn),然后按照切線的方向把線往一邊扯,然后彎了
第四個(gè)和第三個(gè)一樣,不過是兩個(gè)點(diǎn)變成了一個(gè)
第五個(gè),不管了,第六個(gè)把最后的起點(diǎn)和終點(diǎn)鏈接起來
方法的意思知道了,那就開始描線了
首先起點(diǎn)位置選擇,我們拿到拖動(dòng)的點(diǎn),那這個(gè)點(diǎn)的y肯定是線的中間位置(別問為什么,問就是只可意會(huì)不可言傳),線的中間點(diǎn)知道了,那就可以定一個(gè)起點(diǎn)和終點(diǎn)的y值,跨度多少呢,經(jīng)過不斷嘗試,大概200的跨度差不多,所以起點(diǎn)的y值就是changePoint.y - 100,終點(diǎn)就是changePoint + y。然后開始的x,既然從邊緣開始,那不就是屏幕的寬度嘛,so easy,所以起點(diǎn)的位置就是{Screen_Width, changePoint.y - 100},終點(diǎn)就是{Screen_Width, changePoint.y + 100}
所以
第二步
移動(dòng)到一個(gè)點(diǎn) (想啥呢,layer和UIBezierPath都還沒創(chuàng)建呢)
shapeLayer = [CAShapeLayer layer];
shapeLayer.backgroundColor = [UIColor clearColor].CGColor;
shapeLayer.frame = CGRectMake(0, 0, Gesture_SCREEN_WIDTH, Gesture_SCREEN_HEIGHT);
shapeLayer.lineJoin = kCALineJoinRound;
shapeLayer.lineCap = kCALineCapRound;
創(chuàng)建UIBezierPath,開始畫線
UIBezierPath *path = [[UIBezierPath alloc] init];
path.lineWidth=1;
path.usesEvenOddFillRule = YES;
[path moveToPoint:CGPointMake(Gesture_SCREEN_WIDTH, tempPoint.y - 100)];
然后想想那個(gè)曲線,分解一下,第一段像是一個(gè)丿,第二段像是一個(gè)(,第三段像一個(gè)la(不好意思沒找到),那不就來了嘛,小老弟,直接上代碼(想屁吃呢,點(diǎn)還沒確定呢)
首先確定第一段終點(diǎn)位置,要丿到一個(gè)地方,首先y的位置肯定不能是拖動(dòng)點(diǎn)的y的位置,那玩意兒是中心點(diǎn),肯定比它要高,那就高個(gè)20吧(別問,問就是大概加估計(jì))。
再開始確定x的位置,首先比拖動(dòng)點(diǎn)的x要大(為什么大,從左到右,0~屏幕寬度,你說為啥大),然后大多少,憑借我這幾百度的近視眼估計(jì)了一下,大概是拖動(dòng)長(zhǎng)度的四分之一就夠了,那不就來了嘛,x就是tempPoint.x + 10* (Gesture_SCREEN_WIDTH - tempPoint.x) / 40,(有沒有不知道的,不知道算了),第一段終點(diǎn)位置就確定了{tempPoint.x + 10 * (Gesture_SCREEN_WIDTH - tempPoint.x) / 40, tempPoint.y - 20}(tempPoint也就是拖動(dòng)點(diǎn),不過做了一些處理)
終點(diǎn)確定了,那就開始確定往哪個(gè)點(diǎn)彎,經(jīng)過不斷試錯(cuò)我來確定了一個(gè)(Gesture_SCREEN_WIDTH, tempPoint.y - 70),不多解釋,解釋就是憑經(jīng)驗(yàn)(錯(cuò)誤的經(jīng)驗(yàn)),所以代碼就是
[path addQuadCurveToPoint:CGPointMake(tempPoint.x+10* (Gesture_SCREEN_WIDTH- tempPoint.x) /40, tempPoint.y-20) controlPoint:CGPointMake(Gesture_SCREEN_WIDTH, tempPoint.y-70)];
第二段就簡(jiǎn)單了,對(duì)稱一下,就拿到終點(diǎn){tempPoint.x + 10 * (Gesture_SCREEN_WIDTH - tempPoint.x) / 40, tempPoint.y + 20},x不變,起點(diǎn)y減20,終點(diǎn)就加20,控制點(diǎn)根據(jù)第一個(gè)點(diǎn)的方法判斷x就是tempPoint.x - 10 * (Gesture_SCREEN_WIDTH - tempPoint.x) / 40,y自然就是中心點(diǎn)了,控制點(diǎn)就是{tempPoint.x - 10 * (Gesture_SCREEN_WIDTH - tempPoint.x) / 40, tempPoint.y},第三段依葫蘆畫瓢,和第一段一樣,三段畫完,關(guān)門
[path addQuadCurveToPoint:CGPointMake(tempPoint.x + 10 * (Gesture_SCREEN_WIDTH - tempPoint.x) / 40, tempPoint.y + 20) controlPoint:CGPointMake(tempPoint.x - 10 * (Gesture_SCREEN_WIDTH - tempPoint.x) / 40, tempPoint.y)];
[path addQuadCurveToPoint:CGPointMake(Gesture_SCREEN_WIDTH, tempPoint.y + 100) controlPoint:CGPointMake(Gesture_SCREEN_WIDTH, tempPoint.y + 70)];
[path closePath];
然后給layer填充顏色,曲線添加到layer上,perfect!
shapeLayer.fillColor = [_config.backGroundColor colorWithAlphaComponent:_config.backGroundAlpha].CGColor;
shapeLayer.path = path.CGPath;
[Gesture_KeyWindow.layer addSublayer:shapeLayer];
第三步:
背景畫好了,那不得再來個(gè)圖片點(diǎn)綴一下?
再來個(gè)圖片的layer,添加到剛剛的layer上
至于位置嘛,不就跟痘痘里的東西一樣嘛,對(duì)吧,所以直接就是{tempPoint.x + 10, tempPoint.y - 15, 30, 30}
話不多說,直接上代碼。看不懂算求
CALayer *subLayer = [CALayer layer];
subLayer.backgroundColor = [UIColor clearColor].CGColor;
subLayer.contents = (__bridge id _Nullable)([self changeImage:Gesture_ImageWithName(_config.returnImageName) Color:_config.imageColor].CGImage);
subLayer.frame = CGRectMake(tempPoint.x+10, tempPoint.y - 15, 30, 30);
至此,背景大功告成
第四步:
開始添磚加瓦
拖動(dòng)的時(shí)候,不能無限拖唄
所以得限制一下,如果拖動(dòng)到某個(gè)邊界的時(shí)候,繼續(xù)拖就不要改變x值了,我設(shè)置了最大位移距離為40
CGPoint tempPoint = CGPointZero;
if (progressPoint.x < Gesture_SCREEN_WIDTH - 40) {
tempPoint = CGPointMake(Gesture_SCREEN_WIDTH - 40, progressPoint.y);
}else{
tempPoint = progressPoint;
}
既然x設(shè)置限制,y有沒有呢,當(dāng)然也有。當(dāng)我們?cè)谄聊豁敳炕虻撞康臅r(shí)候,起點(diǎn)和終點(diǎn)是不是就可能會(huì)超出屏幕了,所以限制一下y的值,最小不得小于100(為什么是100,看上面),最大不能超過屏幕高度 - 100。
if (progressPoint.y <= 100) {
tempPoint = CGPointMake(tempPoint.x,100)
}else if (progressPoint.y >= Gesture_SCREEN_HEIGHT - 100) {
tempPoint = CGPointMake(tempPoint.x,Gesture_SCREEN_HEIGHT - 100);
}
既然那個(gè)拖動(dòng)展示的曲線要根據(jù)我當(dāng)前的位置,那我是不是只要我接觸點(diǎn)改變,就得重新繪制一次
另外就是直接返回首頁(yè),當(dāng)我拖到一定位置時(shí),幾秒中不動(dòng)就應(yīng)該觸發(fā)返回首頁(yè)的操作,但是?。。〔粍?dòng)?,屏幕感知那么靈敏,呼吸一下都有細(xì)微差距,所以不動(dòng),指的是宏觀上的不動(dòng),不要在意細(xì)小的差別,所以給個(gè)左右精度就好了,我這兒設(shè)置的是左右不超過3就算為不動(dòng)
所以思路有,那就簡(jiǎn)單了,上才藝,上代碼
CGPoint changePoint = [gesture locationInView:Gesture_KeyWindow];
if (gesture.state == UIGestureRecognizerStateBegan) {
farPoint= changePoint;
}
if (gesture.state == UIGestureRecognizerStateChanged) {
if (changePoint.x < farPoint.x)
farPoint= changePoint;
}
if (_config.isCanPopToRootViewController) {
if (homeLeftPoint.x > changePoint.x + 3 || homeLeftPoint.x < changePoint.x -3 ) {
[self createLayer:changePoint];
isPopToRootController = NO;
[NSObject cancelPreviousPerformRequestsWithTarget:self];
[self performSelector:@selector(changeReturnType:) withObject:@(changePoint.x) afterDelay:_config.returnHomeTime];
}
}else{
[self createLayer:changePoint];
}
}
/**
改變返回執(zhí)行類型以及圖標(biāo)
*/
- (void)changeReturnType:(NSNumber *)pointX {
homeLeftPoint = CGPointMake([pointX floatValue],0);
isPopToRootController = YES;
CALayer *layer = [shapeLayer.sublayers firstObject];
layer.contents = (__bridge id _Nullable)([self changeImage:Gesture_ImageWithName(_config.returnHomeImageName) Color:_config.homeImageColor].CGImage);
}
最后就是松手的時(shí)候了,當(dāng)手勢(shì)狀態(tài)為UIGestureRecognizerStateEnded,即是松手了。
那不得簡(jiǎn)簡(jiǎn)單單,直接調(diào)用返回不就完了,想屁吃呢,那個(gè)痘痘不是還展示在屏幕嗎?不打算給摁下去?
所以下一步操作來了,讓這個(gè)痘痘圓潤(rùn)的滾回去
所以咱怎么拖出來的,怎么給收回去不就好了嘛!
但是?。。。?!我不想搞了,你們玩兒吧,我直接簡(jiǎn)單粗暴一點(diǎn),給個(gè)動(dòng)畫,直接他移出去,雖然效果沒有重新繪制好,但是誰叫我懶呢。上代碼
if (gesture.state == UIGestureRecognizerStateEnded) {
CABasicAnimation *anim = [CABasicAnimation animation];
anim.keyPath=@"position";
anim.duration=0.5;
anim.fromValue = [NSValue valueWithCGPoint:shapeLayer.position];
anim.toValue = [NSValue valueWithCGPoint:CGPointMake(shapeLayer.position.x + 55, shapeLayer.position.y)];
anim.fillMode = kCAFillModeForwards;
anim.removedOnCompletion = NO;
[shapeLayer addAnimation:anim forKey:nil];
if (changePoint.x < farPoint.x + 20)
if (!isPopToRootController) {
if (self.delegate && [self.delegate respondsToSelector:@selector(CM_GestureRecognizerPopLastController:currentController:)]) {
UIViewController*lastController =nil;
NSInteger controllerCount =_config.navigationController.viewControllers.count;
if (controllerCount >= 2) {
lastController =_config.navigationController.viewControllers[controllerCount -2];
}
if ([self.delegate CM_GestureRecognizerPopLastController:lastController currentController:_config.navigationController.topViewController]) {
[_config.navigationController popViewControllerAnimated:_config.isShowPopAnimated];
}
}else{
[_config.navigationController popViewControllerAnimated:_config.isShowPopAnimated];
}
}else{
if (self.delegate && [self.delegate respondsToSelector:@selector(CM_GestureRecognizerBackHomeController:)]) {
if ([self.delegate CM_GestureRecognizerBackHomeController:_config.navigationController.viewControllers.firstObject]) {
[_config.navigationController popToRootViewControllerAnimated:_config.isShowPopAnimated];
}
}else{
[_config.navigationController popToRootViewControllerAnimated:_config.isShowPopAnimated];
}
}
}
}
用法
- (void)initScreenPoP {
PopGestureRecognizerManager *manager = [PopGestureRecognizerManager shareManager];
//設(shè)置返回圖片
manager.config.returnImageName = @"icon_pop_jt";
//設(shè)置返回代理,可不設(shè)置,不設(shè)置默認(rèn)返回
//代理的返回值控制是否自動(dòng)調(diào)用返回
manager.delegate = self;
//設(shè)置返回首頁(yè)圖片
manager.config.returnHomeImageName = @"icon_pop_home";
//config傳nil,就使用默認(rèn)的配置,也可以自各兒創(chuàng)建
//頁(yè)面可單獨(dú)修改manager.config的各個(gè)配置
//根控制器默認(rèn)不觸發(fā)返回效果
[manager registerManagerWithConfig:nil completeBlock:^(BOOL isSuccess, NSString *failString) {
NSLog(@"%@",failString);
}];
}
附所有代碼
PopGestureRecognizerManager.h
//
// PopGestureRecognizerManager.h
// ScreenPoP
//
// Created by wr on 2019/7/3.
// Copyright ? 2019年 wanmengchao. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "PopGestureRecognizerManagerConfiger.h"
#import "PopGestureRecognizerDelegate.h"
NS_ASSUME_NONNULL_BEGIN
@interface PopGestureRecognizerManager : NSObject
/// 配置
@property (nonatomic, strong, nonnull) PopGestureRecognizerManagerConfiger *config;
/// 返回代理
@property (nonatomic, weak) id<PopGestureRecognizerDelegate> delegate;
/// 單例
+ (instancetype)shareManager;
/// 注冊(cè)
/// @param config 配置信息
/// @param block 注冊(cè)回調(diào)
- (void)registerManagerWithConfig:(PopGestureRecognizerManagerConfiger * __nullable)config completeBlock:(void(^ __nullable)(BOOL isSuccess, NSString *failString))block;
@end
NS_ASSUME_NONNULL_END
PopGestureRecognizerManager.m
//
// PopGestureRecognizerManager.m
// ScreenPoP
//
// Created by wr on 2019/7/3.
// Copyright ? 2019年 wanmengchao. All rights reserved.
//
#import "PopGestureRecognizerManager.h"
//屏幕大小
#define Gesture_SCREEN_WIDTH [UIScreen mainScreen].bounds.size.width
#define Gesture_SCREEN_HEIGHT [UIScreen mainScreen].bounds.size.height
//顏色宏定義
#define Gesture_COLOR_HEX(hex) Gesture_COLOR_HEXA(hex,1.0f)
#define Gesture_COLOR_HEXA(rgbValue,a) [UIColor colorWithRed:((float)(((rgbValue) & 0xFF0000) >> 16))/255.0 green:((float)(((rgbValue) & 0xFF00)>>8))/255.0 blue: ((float)((rgbValue) & 0xFF))/255.0 alpha:(a)]
#define Gesture_ImageWithName(imgName) [UIImage imageNamed:imgName]
#define Gesture_KeyWindow [[UIApplication sharedApplication] delegate].window
#define PPLog(format, ...) printf("%s",[[NSString stringWithFormat:(format), ##__VA_ARGS__] UTF8String])
static PopGestureRecognizerManager *manager = nil;
@implementation PopGestureRecognizerManager{
CAShapeLayer *shapeLayer;
CGPoint startPoint;
CGPoint farPoint;
CGPoint lastPoint;
CGPoint homeLeftPoint;
BOOL isPopToRootController;
NSTimer *timer;
}
+ (instancetype)shareManager {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
manager = [[PopGestureRecognizerManager alloc] init];
});
return manager;
}
/// 重寫單例對(duì)象的alloc方法, 防止單例對(duì)象被重復(fù)創(chuàng)建
+ (instancetype)alloc {
if (manager) {
// 如果單例對(duì)象存在則拋出異常
NSException *exception = [NSException exceptionWithName:@"重復(fù)創(chuàng)建單例對(duì)象異常" reason:@"單例被重復(fù)創(chuàng)建" userInfo:nil];
[exception raise];
}
return [super alloc];
}
- (instancetype)init {
if (self = [super init]) {
_config = [[PopGestureRecognizerManagerConfiger alloc] init];
}
return self;
}
/**
添加手勢(shì)到window上
*/
- (void)addScreenEdgePanGestureToWindow {
UIScreenEdgePanGestureRecognizer *gesture = [[UIScreenEdgePanGestureRecognizer alloc] initWithTarget:self action:@selector(screenEdgePanGestureExcuteEvent:)];
gesture.edges = UIRectEdgeRight;
[Gesture_KeyWindow addGestureRecognizer:gesture];
}
- (void)registerManagerWithConfig:(PopGestureRecognizerManagerConfiger * __nullable)config completeBlock:(void(^ __nullable)(BOOL isSuccess, NSString *failString))block {
if (config) {
self.config = config;
}
[self addScreenEdgePanGestureToWindow];
if (self.config.returnImageName.length == 0) {
if (block) {
block(YES, @"拖動(dòng)時(shí)返回的圖片未設(shè)置(returnImageName未設(shè)置)");
}
}if (self.config.isCanPopToRootViewController && self.config.returnHomeImageName.length == 0) {
if (block) {
block(YES, @"可以返回主頁(yè)時(shí)(isCanPopToRootViewController = YES),拖動(dòng)展示的圖片未設(shè)置(returnHomeImageName未設(shè)置)");
}
}else{
if (block) {
block(YES, @"當(dāng)前controller為導(dǎo)航控制器的根控制器時(shí),拖動(dòng)無效果");
}
}
#if DEBUG
PPLog(@"==========Manager注冊(cè)信息==========\n");
PPLog(@"NavigationController:%@\n",self.config.navigationController);
PPLog(@"拖動(dòng)時(shí)的背景顏色R:%g G:%g B:%g \n",CGColorGetComponents(self.config.backGroundColor.CGColor)[0] * 255,CGColorGetComponents(self.config.backGroundColor.CGColor)[1] * 255,CGColorGetComponents(self.config.backGroundColor.CGColor)[2] * 255);
PPLog(@"背景顏色Alpha值:%g\n",self.config.backGroundAlpha);
PPLog(@"拖動(dòng)時(shí)展示的圖片:%@\n",self.config.returnImageName);
if (self.config.imageColor) {
PPLog(@"拖動(dòng)時(shí)圖片的顏色:R:%g G:%g B:%g \n",CGColorGetComponents(self.config.imageColor.CGColor)[0] * 255,CGColorGetComponents(self.config.imageColor.CGColor)[1] * 255,CGColorGetComponents(self.config.imageColor.CGColor)[2] * 255);
}else{
PPLog(@"不改變拖動(dòng)時(shí)圖片的顏色\n");
}
PPLog(@"是否跟隨手勢(shì)位置移動(dòng):%@\n",self.config.isFollowGesturePosition ? @"是" : @"否");
PPLog(@"是否可以返回首頁(yè):%@\n",self.config.isCanPopToRootViewController ? @"是" : @"否");
PPLog(@"返回首頁(yè)拖動(dòng)時(shí)展示的圖片:%@\n",self.config.returnImageName);
PPLog(@"返回首頁(yè)拖動(dòng)觸發(fā)時(shí)間:%g\n",self.config.returnHomeTime);
PPLog(@"是否展示返回動(dòng)畫:%@\n",self.config.isShowPopAnimated ? @"是" : @"否");
#endif
}
/**
屏幕邊界手勢(shì)執(zhí)行事件
@param gesture 手勢(shì)
*/
- (void)screenEdgePanGestureExcuteEvent:(UIScreenEdgePanGestureRecognizer *)gesture {
if (_config.navigationController.viewControllers.count == 1) {
return;
}
CGPoint changePoint = [gesture locationInView:Gesture_KeyWindow];
if (gesture.state == UIGestureRecognizerStateBegan) {
farPoint = changePoint;
}
if (gesture.state == UIGestureRecognizerStateChanged) {
if (changePoint.x < farPoint.x) {
farPoint = changePoint;
}
if (_config.isCanPopToRootViewController) {
if (homeLeftPoint.x > changePoint.x + 3 || homeLeftPoint.x < changePoint.x - 3) {
[self createLayer:changePoint];
isPopToRootController = NO;
[NSObject cancelPreviousPerformRequestsWithTarget:self];
[self performSelector:@selector(changeReturnType:) withObject:@(changePoint.x) afterDelay:_config.returnHomeTime];
}
}else{
[self createLayer:changePoint];
}
}
if (gesture.state == UIGestureRecognizerStateEnded) {
CABasicAnimation *anim = [CABasicAnimation animation];
anim.keyPath = @"position";
anim.duration = 0.5;
anim.fromValue = [NSValue valueWithCGPoint:shapeLayer.position];
anim.toValue = [NSValue valueWithCGPoint:CGPointMake(shapeLayer.position.x + 55, shapeLayer.position.y)];
anim.fillMode = kCAFillModeForwards;
anim.removedOnCompletion = NO;
[shapeLayer addAnimation:anim forKey:nil];
if (changePoint.x < farPoint.x + 20) {
if (!isPopToRootController) {
if (self.delegate && [self.delegate respondsToSelector:@selector(CM_GestureRecognizerPopLastController:currentController:)]) {
UIViewController *lastController = nil;
NSInteger controllerCount = _config.navigationController.viewControllers.count;
if (controllerCount >= 2) {
lastController = _config.navigationController.viewControllers[controllerCount - 2];
}
if ([self.delegate CM_GestureRecognizerPopLastController:lastController currentController:_config.navigationController.topViewController]) {
[_config.navigationController popViewControllerAnimated:_config.isShowPopAnimated];
}
}else{
[_config.navigationController popViewControllerAnimated:_config.isShowPopAnimated];
}
}else{
if (self.delegate && [self.delegate respondsToSelector:@selector(CM_GestureRecognizerBackHomeController:)]) {
if ([self.delegate CM_GestureRecognizerBackHomeController:_config.navigationController.viewControllers.firstObject]) {
[_config.navigationController popToRootViewControllerAnimated:_config.isShowPopAnimated];
}
}else{
[_config.navigationController popToRootViewControllerAnimated:_config.isShowPopAnimated];
}
}
}
}
}
/**
創(chuàng)建背景l(fā)ayer
@param progressPoint 滑動(dòng)點(diǎn)
*/
- (void)createLayer:(CGPoint)progressPoint {
CGPoint tempPoint = CGPointZero;
if (progressPoint.x < Gesture_SCREEN_WIDTH - 40) {
tempPoint = CGPointMake(Gesture_SCREEN_WIDTH - 40, progressPoint.y);
}else{
tempPoint = progressPoint;
}
if (_config.isFollowGesturePosition) {
if (progressPoint.y <= 100) {
tempPoint = CGPointMake(tempPoint.x, 100);
}else if (progressPoint.y >= Gesture_SCREEN_HEIGHT - 100) {
tempPoint = CGPointMake(tempPoint.x, Gesture_SCREEN_HEIGHT - 100);
}
}else{
tempPoint = CGPointMake(tempPoint.x, Gesture_SCREEN_HEIGHT / 2);
}
[shapeLayer removeFromSuperlayer];
shapeLayer = [CAShapeLayer layer];
shapeLayer.backgroundColor = [UIColor clearColor].CGColor;
shapeLayer.frame = CGRectMake(0, 0, Gesture_SCREEN_WIDTH, Gesture_SCREEN_HEIGHT);
shapeLayer.lineJoin = kCALineJoinRound;
shapeLayer.lineCap = kCALineCapRound;
CALayer *subLayer = [CALayer layer];
subLayer.backgroundColor = [UIColor clearColor].CGColor;
subLayer.contents = (__bridge id _Nullable)([self changeImage:Gesture_ImageWithName(_config.returnImageName) Color:_config.imageColor].CGImage);
subLayer.frame = CGRectMake(tempPoint.x + 10, tempPoint.y - 15, 30, 30);
UIBezierPath *path = [[UIBezierPath alloc] init];
path.lineWidth = 1;
path.usesEvenOddFillRule = YES;
[path moveToPoint:CGPointMake(Gesture_SCREEN_WIDTH, tempPoint.y - 100)];
[path addQuadCurveToPoint:CGPointMake(tempPoint.x + 10 * (Gesture_SCREEN_WIDTH - tempPoint.x) / 40, tempPoint.y - 20) controlPoint:CGPointMake(Gesture_SCREEN_WIDTH, tempPoint.y - 70)];
[path addQuadCurveToPoint:CGPointMake(tempPoint.x + 10 * (Gesture_SCREEN_WIDTH - tempPoint.x) / 40, tempPoint.y + 20) controlPoint:CGPointMake(tempPoint.x - 0 * (Gesture_SCREEN_WIDTH - tempPoint.x) / 40, tempPoint.y)];
[path addQuadCurveToPoint:CGPointMake(Gesture_SCREEN_WIDTH, tempPoint.y + 100) controlPoint:CGPointMake(Gesture_SCREEN_WIDTH, tempPoint.y + 70)];
[path closePath];
shapeLayer.fillColor = [_config.backGroundColor colorWithAlphaComponent:_config.backGroundAlpha].CGColor;
shapeLayer.path = path.CGPath;
[shapeLayer addSublayer:subLayer];
[Gesture_KeyWindow.layer addSublayer:shapeLayer];
}
/**
改變返回執(zhí)行類型以及圖標(biāo)
*/
- (void)changeReturnType:(NSNumber *)pointX {
homeLeftPoint = CGPointMake([pointX floatValue], 0);
isPopToRootController = YES;
CALayer *layer = [shapeLayer.sublayers firstObject];
layer.contents = (__bridge id _Nullable)([self changeImage:Gesture_ImageWithName(_config.returnHomeImageName) Color:_config.homeImageColor].CGImage);
}
/**
修改圖片顏色
@param image 要改變的圖片
@param color 設(shè)置的顏色
@return 返回圖片
*/
- (UIImage *)changeImage:(UIImage *)image Color:(UIColor * __nullable)color {
if (color) {
UIGraphicsBeginImageContextWithOptions(image.size, NO, image.scale);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(context, 0, image.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextSetBlendMode(context, kCGBlendModeNormal);
CGRect rect = CGRectMake(0, 0, image.size.width, image.size.height);
CGContextClipToMask(context, rect, image.CGImage);
[color setFill];
CGContextFillRect(context, rect);
UIImage*newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}else{
return image;
}
}
@end
PopGestureRecognizerManagerConfiger.h
//
// PopGestureRecognizerManagerConfiger.h
// ScreenPoP
//
// Created by wr on 2019/7/3.
// Copyright ? 2019年 wanmengchao. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface PopGestureRecognizerManagerConfiger : NSObject
/**
導(dǎo)航控制器
默認(rèn)為當(dāng)前window的導(dǎo)航控制器
*/
@property (nonatomic, strong, nullable) UINavigationController *navigationController;
/**
拖動(dòng)時(shí),背景顏色
默認(rèn)為0x999999
*/
@property (nonatomic, strong, nullable) UIColor *backGroundColor;
/**
背景顏色alpha
默認(rèn)為0.5
*/
@property (nonatomic, assign) CGFloat backGroundAlpha;
/**
拖動(dòng)時(shí)展示的圖片
必填,否則無圖片
*/
@property (nonatomic, copy, nonnull) NSString *returnImageName;
/**
用于修改拖動(dòng)時(shí)展示的圖片的顏色
默認(rèn)為不變色即nil
*/
@property (nonatomic, retain, nullable) UIColor *imageColor;
/**
用于修改拖動(dòng)時(shí)展示返回首頁(yè)的圖片的顏色
默認(rèn)為不變色即nil
*/
@property (nonatomic, retain, nullable) UIColor *homeImageColor;
/**
是否跟隨手勢(shì)位置移動(dòng)
默認(rèn)為YES
*/
@property (nonatomic, assign) BOOL isFollowGesturePosition;
/**
是否可以返回首頁(yè)
默認(rèn)為YES
*/
@property (nonatomic, assign) BOOL isCanPopToRootViewController;
/**
返回首頁(yè)拖動(dòng)時(shí)展示的圖片
isCanPopToRootViewController為YES時(shí),必填
*/
@property (nonatomic, copy, nullable) NSString *returnHomeImageName;
/**
返回首頁(yè)用時(shí)
默認(rèn)為1秒
*/
@property (nonatomic, assign) CGFloat returnHomeTime;
/**
是否執(zhí)行返回動(dòng)畫
默認(rèn)為:YES
*/
@property (nonatomic, assign) BOOL isShowPopAnimated;
@end
NS_ASSUME_NONNULL_END
PopGestureRecognizerManagerConfiger.m
//
// PopGestureRecognizerManagerConfiger.m
// ScreenPoP
//
// Created by wr on 2019/7/3.
// Copyright ? 2019年 wanmengchao. All rights reserved.
//
#import "PopGestureRecognizerManagerConfiger.h"
#define Gesture_COLOR_HEX(hex) Gesture_COLOR_HEXA(hex,1.0f)
#define Gesture_COLOR_HEXA(rgbValue,a) [UIColor colorWithRed:((float)(((rgbValue) & 0xFF0000) >> 16))/255.0 green:((float)(((rgbValue) & 0xFF00)>>8))/255.0 blue: ((float)((rgbValue) & 0xFF))/255.0 alpha:(a)]
@implementation PopGestureRecognizerManagerConfiger
- (instancetype)init {
if (self = [super init]) {
_backGroundColor = Gesture_COLOR_HEX(0x999999);
_isFollowGesturePosition = YES;
_isCanPopToRootViewController = YES;
_isShowPopAnimated = YES;
_imageColor = nil;
_returnHomeTime = 1.0f;
_backGroundAlpha = 0.3f;
}
return self;
}
- (UINavigationController *)navigationController {
if (!_navigationController) {
_navigationController = (UINavigationController *)[UIApplication sharedApplication].keyWindow.rootViewController;
}
return _navigationController;
}
@end
PopGestureRecognizerDelegate.h
//
// PopGestureRecognizerDelegate.h
// ScreenPoP
//
// Created by 萬孟超 on 2022/1/19.
// Copyright ? 2022 wanmengchao. All rights reserved.
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@protocol PopGestureRecognizerDelegate <NSObject>
@optional
/// 返回時(shí)代理
/// 重寫返回按鈕時(shí),可實(shí)現(xiàn)此方法處理數(shù)據(jù)
/// @param lastController 上一個(gè)controller
/// @param currentController 當(dāng)前controller
/// @return 是否自動(dòng)返回上一個(gè)controller
- (BOOL)CM_GestureRecognizerPopLastController:(UIViewController *)lastController currentController:(UIViewController *)currentController;
/// 返回首頁(yè)代理
/// @param currentController 當(dāng)前controller
/// @return 是否自動(dòng)返回主頁(yè)
- (BOOL)CM_GestureRecognizerBackHomeController:(UIViewController *)currentController;
@end
NS_ASSUME_NONNULL_END
至此,搞定收工
附demo地址:ScreenPop: 仿Android左滑返回
Swift版的就不搞了,實(shí)現(xiàn)思路一樣的!