閑來無事昙读,整點活兒干干!
不整別的舌缤,先來巴拉巴拉這玩意兒怎么玩兒箕戳。
開局一張圖,內(nèi)容全靠騙
開整
首先需要滑動国撵,那肯定得要來一個滑動的手勢陵吸,既然滑動手勢有了,加哪介牙?既然手勢作為全局生效壮虫,那肯定不能加在單個的view
上,所以直接加在window
上环础,這樣不就都有了嘛囚似。
UIScreenEdgePanGestureRecognizer *gesture = [[UIScreenEdgePanGestureRecognizer alloc] initWithTarget:self action:**@selector(screenEdgePanGestureExcuteEvent:)];
gesture.edges = UIRectEdgeRight;
[Gesture_KeyWindow addGestureRecognizer:gesture];
既然手勢加上了,那不得來個響應(yīng)事件线得。
如何去實現(xiàn)呢饶唤,拖動的時候要像臉上的痘痘一樣,冒出個頭贯钩,直接加個view
募狂,然后做動畫??,你來角雷,我整不動祸穷,別問我為什么,問就是我這么干過勺三,結(jié)果把路走死了雷滚。
那就想想其他辦法,那不得有個玩意兒叫layer
嘛吗坚。那我添加個畫布多刺激祈远,想加啥就加啥。
說干就干商源。
第一步:
既然要拖车份,那就得先拿到位置,對吧炊汹,這個沒啥問題吧(有問題的躬充,請?zhí)岢瞿愕膯栴},我不回答,我怕我打死你)充甚。
CGPoint changePoint = [gesture locationInView:Gesture_KeyWindow];
先忽略細節(jié)以政,開始畫豬,咱得先畫個豬腦袋吧伴找,至少知道你畫的是個啥玩意兒盈蛮,先整個效果都!
點拿到了技矮,那就要開始拖了抖誉。那我們是不是得要知道兩個狀態(tài)啊,我到底是剛摁下去呢衰倦,還是在拖動袒炉,對吧,所以就有倆貨樊零,UIGestureRecognizerStateBegan我磁、UIGestureRecognizerStateChanged
,一個是咱剛摁下去的狀態(tài)驻襟,一個是在滑的狀態(tài)夺艰,好了,這兩個狀態(tài)知道了沉衣,在UIGestureRecognizerStateBegan
狀態(tài)是記錄開始的點郁副,在UIGestureRecognizerStateChanged
狀態(tài)的時候記錄變化點。
開始動用你的腦瓜子YY一下豌习,咱拖的時候不是有一個痘痘一樣凸起的東西嗎存谎?那咱先畫那個玩意兒。想想那個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;
第一個移到一個點嘱巾,這不難理解,既然要畫那不得知道從那開始诫钓,對吧旬昭!
第二個添加一條線,還是直的菌湃,想想那個曲線问拘,明明是彎的好吧,所以pass掉
第三個畫的是彎的線,大致就是本來是直的線段骤坐,現(xiàn)在來了倆點绪杏,然后按照切線的方向把線往一邊扯,然后彎了
第四個和第三個一樣纽绍,不過是兩個點變成了一個
第五個蕾久,不管了,第六個把最后的起點和終點鏈接起來
方法的意思知道了拌夏,那就開始描線了
首先起點位置選擇僧著,我們拿到拖動的點,那這個點的y肯定是線的中間位置(別問為什么障簿,問就是只可意會不可言傳)盹愚,線的中間點知道了,那就可以定一個起點和終點的y值站故,跨度多少呢杯拐,經(jīng)過不斷嘗試,大概200
的跨度差不多世蔗,所以起點的y
值就是changePoint.y - 100
端逼,終點就是changePoint + y
。然后開始的x污淋,既然從邊緣開始顶滩,那不就是屏幕的寬度嘛,so easy寸爆,所以起點的位置就是{Screen_Width, changePoint.y - 100}
礁鲁,終點就是{Screen_Width, changePoint.y + 100}
所以
第二步
移動到一個點 (想啥呢,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)];
然后想想那個曲線仅醇,分解一下,第一段像是一個丿魔种,第二段像是一個(析二,第三段像一個la(不好意思沒找到),那不就來了嘛节预,小老弟叶摄,直接上代碼(想屁吃呢,點還沒確定呢)
首先確定第一段終點位置安拟,要丿到一個地方蛤吓,首先y的位置肯定不能是拖動點的y的位置,那玩意兒是中心點糠赦,肯定比它要高会傲,那就高個20
吧(別問锅棕,問就是大概加估計)。
再開始確定x的位置淌山,首先比拖動點的x要大(為什么大哲戚,從左到右,0~屏幕寬度
艾岂,你說為啥大)顺少,然后大多少,憑借我這幾百度的近視眼估計了一下王浴,大概是拖動長度的四分之一就夠了脆炎,那不就來了嘛,x
就是tempPoint.x + 10* (Gesture_SCREEN_WIDTH - tempPoint.x) / 40
氓辣,(有沒有不知道的秒裕,不知道算了),第一段終點位置就確定了{tempPoint.x + 10 * (Gesture_SCREEN_WIDTH - tempPoint.x) / 40, tempPoint.y - 20}
(tempPoint
也就是拖動點钞啸,不過做了一些處理)
終點確定了几蜻,那就開始確定往哪個點彎,經(jīng)過不斷試錯我來確定了一個(Gesture_SCREEN_WIDTH, tempPoint.y - 70)
体斩,不多解釋梭稚,解釋就是憑經(jīng)驗(錯誤的經(jīng)驗),所以代碼就是
[path addQuadCurveToPoint:CGPointMake(tempPoint.x+10* (Gesture_SCREEN_WIDTH- tempPoint.x) /40, tempPoint.y-20) controlPoint:CGPointMake(Gesture_SCREEN_WIDTH, tempPoint.y-70)];
第二段就簡單了絮吵,對稱一下弧烤,就拿到終點{tempPoint.x + 10 * (Gesture_SCREEN_WIDTH - tempPoint.x) / 40, tempPoint.y + 20}
,x
不變蹬敲,起點y
減20
暇昂,終點就加20
,控制點根據(jù)第一個點的方法判斷x
就是tempPoint.x - 10 * (Gesture_SCREEN_WIDTH - tempPoint.x) / 40
伴嗡,y
自然就是中心點了急波,控制點就是{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];
第三步:
背景畫好了价认,那不得再來個圖片點綴一下?
再來個圖片的layer
自娩,添加到剛剛的layer
上
至于位置嘛用踩,不就跟痘痘里的東西一樣嘛渠退,對吧,所以直接就是{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);
至此惠奸,背景大功告成
第四步:
開始添磚加瓦
拖動的時候梅誓,不能無限拖唄
所以得限制一下,如果拖動到某個邊界的時候佛南,繼續(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
有沒有呢嗅回,當然也有及穗。當我們在屏幕頂部或底部的時候,起點和終點是不是就可能會超出屏幕了绵载,所以限制一下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);
}
既然那個拖動展示的曲線要根據(jù)我當前的位置,那我是不是只要我接觸點改變懂版,就得重新繪制一次
另外就是直接返回首頁著摔,當我拖到一定位置時,幾秒中不動就應(yīng)該觸發(fā)返回首頁的操作定续,但是5亍!私股!不動摹察?,屏幕感知那么靈敏倡鲸,呼吸一下都有細微差距供嚎,所以不動,指的是宏觀上的不動峭状,不要在意細小的差別克滴,所以給個左右精度就好了,我這兒設(shè)置的是左右不超過3就算為不動
所以思路有优床,那就簡單了劝赔,上才藝,上代碼
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í)行類型以及圖標
*/
- (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);
}
最后就是松手的時候了胆敞,當手勢狀態(tài)為UIGestureRecognizerStateEnded
着帽,即是松手了杂伟。
那不得簡簡單單,直接調(diào)用返回不就完了仍翰,想屁吃呢赫粥,那個痘痘不是還展示在屏幕嗎?不打算給摁下去予借?
所以下一步操作來了越平,讓這個痘痘圓潤的滾回去
所以咱怎么拖出來的,怎么給收回去不就好了嘛灵迫!
但是P省!9暝佟J檎ⅰ!我不想搞了利凑,你們玩兒吧浆劲,我直接簡單粗暴一點,給個動畫哀澈,直接他移出去牌借,雖然效果沒有重新繪制好,但是誰叫我懶呢割按。上代碼
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è)置默認返回
//代理的返回值控制是否自動調(diào)用返回
manager.delegate = self;
//設(shè)置返回首頁圖片
manager.config.returnHomeImageName = @"icon_pop_home";
//config傳nil适荣,就使用默認的配置现柠,也可以自各兒創(chuàng)建
//頁面可單獨修改manager.config的各個配置
//根控制器默認不觸發(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;
/// 注冊
/// @param config 配置信息
/// @param block 注冊回調(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;
}
/// 重寫單例對象的alloc方法, 防止單例對象被重復(fù)創(chuàng)建
+ (instancetype)alloc {
if (manager) {
// 如果單例對象存在則拋出異常
NSException *exception = [NSException exceptionWithName:@"重復(fù)創(chuàng)建單例對象異常" reason:@"單例被重復(fù)創(chuàng)建" userInfo:nil];
[exception raise];
}
return [super alloc];
}
- (instancetype)init {
if (self = [super init]) {
_config = [[PopGestureRecognizerManagerConfiger alloc] init];
}
return self;
}
/**
添加手勢到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, @"拖動時返回的圖片未設(shè)置(returnImageName未設(shè)置)");
}
}if (self.config.isCanPopToRootViewController && self.config.returnHomeImageName.length == 0) {
if (block) {
block(YES, @"可以返回主頁時(isCanPopToRootViewController = YES),拖動展示的圖片未設(shè)置(returnHomeImageName未設(shè)置)");
}
}else{
if (block) {
block(YES, @"當前controller為導(dǎo)航控制器的根控制器時弛矛,拖動無效果");
}
}
#if DEBUG
PPLog(@"==========Manager注冊信息==========\n");
PPLog(@"NavigationController:%@\n",self.config.navigationController);
PPLog(@"拖動時的背景顏色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(@"拖動時展示的圖片:%@\n",self.config.returnImageName);
if (self.config.imageColor) {
PPLog(@"拖動時圖片的顏色: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(@"不改變拖動時圖片的顏色\n");
}
PPLog(@"是否跟隨手勢位置移動:%@\n",self.config.isFollowGesturePosition ? @"是" : @"否");
PPLog(@"是否可以返回首頁:%@\n",self.config.isCanPopToRootViewController ? @"是" : @"否");
PPLog(@"返回首頁拖動時展示的圖片:%@\n",self.config.returnImageName);
PPLog(@"返回首頁拖動觸發(fā)時間:%g\n",self.config.returnHomeTime);
PPLog(@"是否展示返回動畫:%@\n",self.config.isShowPopAnimated ? @"是" : @"否");
#endif
}
/**
屏幕邊界手勢執(zhí)行事件
@param gesture 手勢
*/
- (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 滑動點
*/
- (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í)行類型以及圖標
*/
- (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)航控制器
默認為當前window的導(dǎo)航控制器
*/
@property (nonatomic, strong, nullable) UINavigationController *navigationController;
/**
拖動時够吩,背景顏色
默認為0x999999
*/
@property (nonatomic, strong, nullable) UIColor *backGroundColor;
/**
背景顏色alpha
默認為0.5
*/
@property (nonatomic, assign) CGFloat backGroundAlpha;
/**
拖動時展示的圖片
必填,否則無圖片
*/
@property (nonatomic, copy, nonnull) NSString *returnImageName;
/**
用于修改拖動時展示的圖片的顏色
默認為不變色即nil
*/
@property (nonatomic, retain, nullable) UIColor *imageColor;
/**
用于修改拖動時展示返回首頁的圖片的顏色
默認為不變色即nil
*/
@property (nonatomic, retain, nullable) UIColor *homeImageColor;
/**
是否跟隨手勢位置移動
默認為YES
*/
@property (nonatomic, assign) BOOL isFollowGesturePosition;
/**
是否可以返回首頁
默認為YES
*/
@property (nonatomic, assign) BOOL isCanPopToRootViewController;
/**
返回首頁拖動時展示的圖片
isCanPopToRootViewController為YES時丈氓,必填
*/
@property (nonatomic, copy, nullable) NSString *returnHomeImageName;
/**
返回首頁用時
默認為1秒
*/
@property (nonatomic, assign) CGFloat returnHomeTime;
/**
是否執(zhí)行返回動畫
默認為: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
/// 返回時代理
/// 重寫返回按鈕時周循,可實現(xiàn)此方法處理數(shù)據(jù)
/// @param lastController 上一個controller
/// @param currentController 當前controller
/// @return 是否自動返回上一個controller
- (BOOL)CM_GestureRecognizerPopLastController:(UIViewController *)lastController currentController:(UIViewController *)currentController;
/// 返回首頁代理
/// @param currentController 當前controller
/// @return 是否自動返回主頁
- (BOOL)CM_GestureRecognizerBackHomeController:(UIViewController *)currentController;
@end
NS_ASSUME_NONNULL_END
至此,搞定收工
附demo地址:ScreenPop: 仿Android左滑返回
Swift版的就不搞了万俗,實現(xiàn)思路一樣的湾笛!