闲来无事,整点活儿干干!
不整别的,先来巴拉巴拉这玩意儿怎么玩儿。
开局一张图,内容全靠骗
开整
首先需要滑动,那肯定得要来一个滑动的手势,既然滑动手势有了,加哪?既然手势作为全局生效,那肯定不能加在单个的view
上,所以直接加在window
上,这样不就都有了嘛。
UIScreenEdgePanGestureRecognizer *gesture = [[UIScreenEdgePanGestureRecognizer alloc] initWithTarget:self action:**@selector(screenEdgePanGestureExcuteEvent:)];
gesture.edges = UIRectEdgeRight;
[Gesture_KeyWindow addGestureRecognizer:gesture];
既然手势加上了,那不得来个响应事件。
如何去实现呢,拖动的时候要像脸上的痘痘一样,冒出个头,直接加个view
,然后做动画😓,你来,我整不动,别问我为什么,问就是我这么干过,结果把路走死了。
那就想想其他办法,那不得有个玩意儿叫layer
嘛。那我添加个画布多刺激,想加啥就加啥。
说干就干。
第一步:
既然要拖,那就得先拿到位置,对吧,这个没啥问题吧(有问题的,请提出你的问题,我不回答,我怕我打死你)。
CGPoint changePoint = [gesture locationInView:Gesture_KeyWindow];
先忽略细节,开始画猪,咱得先画个猪脑袋吧,至少知道你画的是个啥玩意儿,先整个效果都!
点拿到了,那就要开始拖了。那我们是不是得要知道两个状态啊,我到底是刚摁下去呢,还是在拖动,对吧,所以就有俩货,UIGestureRecognizerStateBegan、UIGestureRecognizerStateChanged
,一个是咱刚摁下去的状态,一个是在滑的状态,好了,这两个状态知道了,在UIGestureRecognizerStateBegan
状态是记录开始的点,在UIGestureRecognizerStateChanged
状态的时候记录变化点。
开始动用你的脑瓜子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掉
第三个画的是弯的线,大致就是本来是直的线段,现在来了俩点,然后按照切线的方向把线往一边扯,然后弯了
第四个和第三个一样,不过是两个点变成了一个
第五个,不管了,第六个把最后的起点和终点链接起来
方法的意思知道了,那就开始描线了
首先起点位置选择,我们拿到拖动的点,那这个点的y肯定是线的中间位置(别问为什么,问就是只可意会不可言传),线的中间点知道了,那就可以定一个起点和终点的y值,跨度多少呢,经过不断尝试,大概200
的跨度差不多,所以起点的y
值就是changePoint.y - 100
,终点就是changePoint + y
。然后开始的x,既然从边缘开始,那不就是屏幕的宽度嘛,so easy,所以起点的位置就是{Screen_Width, changePoint.y - 100}
,终点就是{Screen_Width, changePoint.y + 100}
所以
第二步
移动到一个点 (想啥呢,layer
和UIBezierPath
都还没创建呢)
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;
创建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
也就是拖动点,不过做了一些处理)
终点确定了,那就开始确定往哪个点弯,经过不断试错我来确定了一个(Gesture_SCREEN_WIDTH, tempPoint.y - 70)
,不多解释,解释就是凭经验(错误的经验),所以代码就是
[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
,控制点根据第一个点的方法判断x
就是tempPoint.x - 10 * (Gesture_SCREEN_WIDTH - tempPoint.x) / 40
,y
自然就是中心点了,控制点就是{tempPoint.x - 10 * (Gesture_SCREEN_WIDTH - tempPoint.x) / 40, tempPoint.y}
,第三段依葫芦画瓢,和第一段一样,三段画完,关门
[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
值了,我设置了最大位移距离为40
CGPoint tempPoint = CGPointZero;
if (progressPoint.x < Gesture_SCREEN_WIDTH - 40) {
tempPoint = CGPointMake(Gesture_SCREEN_WIDTH - 40, progressPoint.y);
}else{
tempPoint = progressPoint;
}
既然x
设置限制,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);
}
既然那个拖动展示的曲线要根据我当前的位置,那我是不是只要我接触点改变,就得重新绘制一次
另外就是直接返回首页,当我拖到一定位置时,几秒中不动就应该触发返回首页的操作,但是!!!不动?,屏幕感知那么灵敏,呼吸一下都有细微差距,所以不动,指的是宏观上的不动,不要在意细小的差别,所以给个左右精度就好了,我这儿设置的是左右不超过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];
}
}
/**
改变返回执行类型以及图标
*/
- (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);
}
最后就是松手的时候了,当手势状态为UIGestureRecognizerStateEnded
,即是松手了。
那不得简简单单,直接调用返回不就完了,想屁吃呢,那个痘痘不是还展示在屏幕吗?不打算给摁下去?
所以下一步操作来了,让这个痘痘圆润的滚回去
所以咱怎么拖出来的,怎么给收回去不就好了嘛!
但是!!!!!我不想搞了,你们玩儿吧,我直接简单粗暴一点,给个动画,直接他移出去,虽然效果没有重新绘制好,但是谁叫我懒呢。上代码
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];
//设置返回图片
manager.config.returnImageName = @"icon_pop_jt";
//设置返回代理,可不设置,不设置默认返回
//代理的返回值控制是否自动调用返回
manager.delegate = self;
//设置返回首页图片
manager.config.returnHomeImageName = @"icon_pop_home";
//config传nil,就使用默认的配置,也可以自各儿创建
//页面可单独修改manager.config的各个配置
//根控制器默认不触发返回效果
[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 注册回调
- (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方法, 防止单例对象被重复创建
+ (instancetype)alloc {
if (manager) {
// 如果单例对象存在则抛出异常
NSException *exception = [NSException exceptionWithName:@"重复创建单例对象异常" reason:@"单例被重复创建" 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, @"拖动时返回的图片未设置(returnImageName未设置)");
}
}if (self.config.isCanPopToRootViewController && self.config.returnHomeImageName.length == 0) {
if (block) {
block(YES, @"可以返回主页时(isCanPopToRootViewController = YES),拖动展示的图片未设置(returnHomeImageName未设置)");
}
}else{
if (block) {
block(YES, @"当前controller为导航控制器的根控制器时,拖动无效果");
}
}
#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(@"返回首页拖动触发时间:%g\n",self.config.returnHomeTime);
PPLog(@"是否展示返回动画:%@\n",self.config.isShowPopAnimated ? @"是" : @"否");
#endif
}
/**
屏幕边界手势执行事件
@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];
}
}
}
}
}
/**
创建背景layer
@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];
}
/**
改变返回执行类型以及图标
*/
- (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 设置的颜色
@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
/**
导航控制器
默认为当前window的导航控制器
*/
@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;
/**
是否执行返回动画
默认为: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
/// 返回时代理
/// 重写返回按钮时,可实现此方法处理数据
/// @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版的就不搞了,实现思路一样的!