首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >iOS右滑返回的实现【修订】

iOS右滑返回的实现【修订】

作者头像
公众号iOS逆向
发布于 2021-08-25 09:07:45
发布于 2021-08-25 09:07:45
1.8K00
代码可运行
举报
文章被收录于专栏:iOS逆向与安全iOS逆向与安全
运行总次数:0
代码可运行

引言

原理:利用系统的返回手势interactivePopGestureRecognizer进行实现

使用场景:返回按钮有点小,不好触发返回时,可借助右滑返回来提升用户体验

在这里插入图片描述

I 、添加右滑返回手势

若项目有全局的UINavigationController基类,给页面添加右滑返回手势

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@implementation NavigationController

- (void)viewDidLoad
{
    [super viewDidLoad];
    //设置右滑返回手势的代理为自身
    __weak typeof(self) weakself = self;
    if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
        self.interactivePopGestureRecognizer.delegate = (id)weakself;
    }
}

#pragma mark - UIGestureRecognizerDelegate
//这个方法是在手势将要激活前调用:返回YES允许右滑手势的激活,返回NO不允许右滑手势的激活
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
    if (gestureRecognizer == self.interactivePopGestureRecognizer) {
        //屏蔽调用rootViewController的滑动返回手势,避免右滑返回手势引起死机问题
        if (self.viewControllers.count < 2 ||
 self.visibleViewController == [self.viewControllers objectAtIndex:0]) {
            return NO;
        }
    }
    //这里就是非右滑手势调用的方法啦,统一允许激活
    return YES;
}

II、QMUI导致右滑返回没有生效的解决方法

先来看看QMUI如何实现实现右滑返回?

2.1 UINavigationController (QMUI)进行控制右滑返回

QMUI使用分类UINavigationController (QMUI)方式进行控制右滑返回,具体核心代码如下

  1. 重写viewDidLoad设置右滑返回手势的代理为自身
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
        ExtendImplementationOfVoidMethodWithoutArguments([UINavigationController class], @selector(viewDidLoad), ^(UINavigationController *selfObject) {
            selfObject.qmui_interactivePopGestureRecognizerDelegate = selfObject.interactivePopGestureRecognizer.delegate;
            selfObject.interactivePopGestureRecognizer.delegate = (id<UIGestureRecognizerDelegate>)selfObject;
        });


  1. gestureRecognizerShouldBegin

这个方法是在手势将要激活前调用:返回YES允许右滑手势的激活,返回NO不允许右滑手势的激活

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
    if (gestureRecognizer == self.interactivePopGestureRecognizer) {
        BOOL canPopViewController = [self canPopViewController:self.topViewController byPopGesture:YES];
        if (canPopViewController) {
            if ([self.qmui_interactivePopGestureRecognizerDelegate respondsToSelector:_cmd]) {
                return [self.qmui_interactivePopGestureRecognizerDelegate gestureRecognizerShouldBegin:gestureRecognizer];
            } else {
                return NO;
            }
        } else {
            return NO;
        }
    }
    return YES;
}


  1. iOS 13.4 开始会优先询问shouldReceiveEvent方法,只有返回 YES 后才会继续后续的逻辑
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制

- (BOOL)_gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveEvent:(UIEvent *)event {
    if (gestureRecognizer == self.interactivePopGestureRecognizer) {
        NSObject <UIGestureRecognizerDelegate> *originGestureDelegate = self.qmui_interactivePopGestureRecognizerDelegate;
        if ([originGestureDelegate respondsToSelector:_cmd]) {
            BOOL originalValue = YES;
            [originGestureDelegate qmui_performSelector:_cmd withPrimitiveReturnValue:&originalValue arguments:&gestureRecognizer, &event, nil];
            if (!originalValue && [self shouldForceEnableInteractivePopGestureRecognizer]) {
                return YES;
            }
            return originalValue;
        }
    }
    return YES;
}


其中在第三步中shouldForceEnableInteractivePopGestureRecognizer调用了UINavigationControllerBackButtonHandlerProtocol协议的forceEnableInteractivePopGestureRecognizer 进行判定是否返回。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
- (BOOL)shouldForceEnableInteractivePopGestureRecognizer {
    UIViewController *viewController = [self topViewController];
    return self.viewControllers.count > 1 && self.interactivePopGestureRecognizer.enabled && [viewController respondsToSelector:@selector(forceEnableInteractivePopGestureRecognizer)] && [viewController forceEnableInteractivePopGestureRecognizer];
}

当自定义了leftBarButtonItem按钮之后,系统的手势返回就失效了。 可以通过forceEnableInteractivePopGestureRecognizer来决定要不要把那个手势返回强制加回来。当 interactivePopGestureRecognizer.enabled = NO 或者当前UINavigationController堆栈的viewControllers小于2的时候此方法无效。

自定义了leftBarButtonItem按钮

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated{
    
    viewController.hidesBottomBarWhenPushed = self.viewControllers.count == 1;

    
    if (self.viewControllers.count>0) {
        
        [self setNavigationBarHidden:NO animated:NO];
//        viewController.hidesBottomBarWhenPushed =YES;
        //设置左边按钮

        UIBarButtonItem *backItem      =nil;
        
        
        if ([viewController respondsToSelector:@selector(KNbackAction)]) {

             backItem =[[UIBarButtonItem alloc]initWithImage:[UIImage imageNamed:QCTNAVicon_left] style:0 target:viewController action:@selector(KNbackAction)];
            

            
            
        }else{
            
            backItem =[[UIBarButtonItem alloc]initWithImage:[UIImage imageNamed:QCTNAVicon_left] style:0 target:self action:@selector(backAction)];

            
            
        }
        
            viewController.navigationItem.leftBarButtonItems = @[backItem];


        



        
        
    }
    [super pushViewController:viewController animated:animated];

}

2.2 解决方法

所以当你自定义导航栏(自定义了leftBarButtonItem按钮)没采用系统的默认的实现,发生当前不可以手势返回,可先检查为什么当前状态,系统不允许你的手势返回,例如是否隐藏了 navigationBar,或者隐藏了系统的返回按钮?

比如push的时候,自定义了leftBarButtonItem按钮了,你可以采用分类方式往UIViewController 添加forceEnableInteractivePopGestureRecognizer方法将手势返回强制加回来

2.3 动态添加方法

使用场景:

  1. 在消息发送和消息转发时会用到动态添加方法
  2. 全局控制返回手势

下面的+addMethod方法有三个参数,第一个参数是要添加方法的类,第二个参数是方法的SEL,第三个参数则是提供方法实现的SEL。

使用class_getInstanceMethod()method_getImplementation()获取相应SEL。 下方的IMP其实就是Implementation的方法缩写,获取到相应的方法实现后,然后再调用class_addMethod()方法将IMP与SEL进行绑定即可。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制

/**
 往类上添加新的方法与其实现
 
 @param class 相应的类
 @param methodSel 添加的方法
 @param methodSelImpl 包含方法实现的SEL
 */
+ (void)addMethod:(Class)class method:(SEL)methodSel method:(SEL)methodSelImpl {
    Method method = class_getInstanceMethod(class, methodSelImpl);
    IMP methodIMP = method_getImplementation(method);
    const char *types = method_getTypeEncoding(method);
    class_addMethod(class, methodSel, methodIMP, types);
}

往UIViewController 添加forceEnableInteractivePopGestureRecognizer方法将手势返回强制加回来

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    @implementation UIViewController (ERPPresent13)
+ (void)load {

    [self addMethod:self.class method:@selector(forceEnableInteractivePopGestureRecognizer) method:@selector(kunnan_forceEnableInteractivePopGestureRecognizer)];
    
    
}

- (BOOL)kunnan_forceEnableInteractivePopGestureRecognizer {

    
    return YES;
    


}



在这里插入图片描述

III、自定义导航条的rightBarButtonItem

自定义导航条的rightBarButtonItem,采用initWithCustomView:rightBtn设置rightBtn.frame,让文字更大,更容易点击

https://kunnan.blog.csdn.net/article/details/77675855

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
-(void) setuprightBtn{
    
    
    UIButton *rightBtn = [UIButton buttonWithType:UIButtonTypeCustom];
    rightBtn.frame = CGRectMake(0, 0, 44, 44);
//    [rightBtn setImage:[UIImage imageNamed:@"icon_shoukuan_shaixuan_n"] forState:UIControlStateNormal];
    [rightBtn setTitle:@"编辑" forState:UIControlStateNormal];
    
    [rightBtn setTitleColor:kcellColor forState:UIControlStateNormal];

    [rightBtn addTarget:self action:@selector(gotoEditVC) forControlEvents:UIControlEventTouchUpInside];
    [rightBtn setImageEdgeInsets:UIEdgeInsetsMake(0, 22, 0, 0)];
    
    UIBarButtonItem *rightButtonItem = [[UIBarButtonItem alloc]initWithCustomView:rightBtn];
    
    
    self.navigationItem.rightBarButtonItem = rightButtonItem;

    self.navigationItem.rightBarButtonItem.customView.hidden = YES;



}


see also

iOS运行时API应用:

1、实现路由(接口控制app跳任意界面 ) 2、获取修改对象的成员属性 3、动态添加/交换方法的实现 4、属性关联 https://kunnan.blog.csdn.net/article/details/112822138

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-08-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 iOS逆向 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
判断前台 Activity 是否属于本进程
约定:文中表述说一个 Activity 处于激活状态是指它是屏幕上当前展示的 Activity,且没有被 Dialog 覆盖。
mzlogin
2020/04/16
1K0
关于获取当前Activity的一些思考
在Android开发过程中,我们有时候需要获取当前的Activity实例,比如弹出Dialog操作,必须要用到这个。关于如何实现由很多种思路,这其中有的简单,有的复杂,这里简单总结一下个人的一些经验吧。
技术小黑屋
2018/09/05
1.9K0
Android经典面试题之实战经验分享:如何简单实现App的前后台监听判断
在Android中判断一个应用是否处于前台或后台,可以使用ActivityLifecycleCallbacks 和 ProcessLifecycleOwner。在Kotlin中,我们可以利用下面这些工具来实现这个功能。
AntDream
2024/07/31
1990
Android经典面试题之实战经验分享:如何简单实现App的前后台监听判断
Android Jetpack系列之Lifecycle
Lifecycle是Jetpack架构组件中用来感知生命周期的组件,使用Lifecycles可以帮助我们写出和生命周期相关更简洁更易维护的代码。
黄林晴
2020/05/21
5940
Android registerActivityLifecycleCallbacks 使用
使用这个类,我们可以很方便的监听到 Activity 的状态,从而可以判断 APP 是否在前台或者后台等。
程序员飞飞
2020/02/27
2.7K0
「Leakcanary 源码分析」看这一篇就够了
Reference 把内存分为 4 种状态,Active 、 Pending 、 Enqueued 、 Inactive。
程序亦非猿
2019/08/16
7850
「Leakcanary 源码分析」看这一篇就够了
Android中实现用户无感知处理后台崩溃
正所谓,要想没有bug,就一行代码也不写。App到了用户的手里,肯定是崩溃越少越好。Android中的崩溃处理和iOS不太一样,iOS崩溃通常是闪退,而安卓会出现如下的蹩脚的对话框
技术小黑屋
2018/08/29
1.4K1
Android中实现用户无感知处理后台崩溃
Android:全面解析熟悉而陌生 的 Application 类使用
前言 Applicaiton类在 Android开发中非常常见,可是你真的了解Applicaiton类吗? 本文将全面解析Applicaiton类,包括特点、方法介绍、应用场景和具体使用,希望你们会喜
非著名程序员
2018/02/02
2K0
Android:全面解析熟悉而陌生 的 Application 类使用
Android高级工程师面试实战,您会挂么?
xxx公司面试总结 面试形势 群聊(2个面试官+HR+自己) 面试流程 自我介绍 面试官根据你的介绍开始问 你对我们公司有什么想了解的么(复活卡,要时回到没有了也就没有了,可以让面试官给自己提一下建议) 面试题回忆,没有先后顺序 项目架构,组件化架构(他反而没问插件化) Android 事件分发机制(问到源码调用细节) 反射怎么调用一个类的私有方法(这里也是问细节,2个方法的区别) Method method=clazz.getDeclaredMethod(name);//可以调用本类中的所有方法(不包括
用户1155943
2019/05/25
4280
全解系列:内存泄漏定位工具LeakCanary!
在日常开发中,不可避免的会遇到内存泄漏的问题,从而导致App的内存使用紧张,严重的情况还会导致App的卡顿甚至是奔溃,所以需要开发人员解决这些内存泄漏的问题。
胡飞洋
2020/09/17
5.7K0
【Android 应用开发】 Application 使用分析
博客地址 : http://blog.csdn.net/shulianghan/article/details/40737419
韩曙亮
2023/03/27
8760
【Android 应用开发】 Application 使用分析
Android 全埋点解决方案
但也不是说全埋点就一定没有弊端,比如扩展性较差。 经过调研,实际上都是以全埋点为主、手动埋点为辅的情况,从而达到比较理想的埋点效果。
yechaoa
2022/06/10
9310
Android内存泄漏检测利器:LeakCanary
到这里你就可以检测到Activity的内容泄露了。其实现原理是设置Application的ActivityLifecycleCallbacks方法监控所有Activity的生命周期回调。内部实现代码为
技术小黑屋
2018/09/05
1.2K0
LeakCanary笔记
RefWatcher 的代理类。通过注册 ActivityLifecycleCallbacks 回调,当 Activity 调用 onDestroy() 时进行一次内存泄漏检查,执行 RefWatcher 的 watch 方法,检测该 Activity 是否发生内存泄露。
续写经典
2018/08/28
3350
ASM字节码插桩
以往的埋点方式都是人为进行定义名称和选择性埋点,版本迭代多次后造成埋点数量持续增加。
没关系再继续努力
2021/11/27
1.1K0
Android仿微信文章悬浮窗效果
前些日子跟朋友聊天,朋友Z果粉,前些天更新了微信,说微信出了个好方便的功能啊,我问是啥功能啊,看看我大Android有没有,他说现在阅读公众号文章如果有人给你发微信你可以把这篇文章当作悬浮窗悬浮起来,方便你聊完天不用找继续阅读,听完是不是觉得这叫啥啊,我大Android微信版不是早就有这个功能了吗,我看文章的时候看到过有这个悬浮按钮,但是我一直没有使用过,试了一下还是挺方便的,就想着自己实现一下这个功能,下面看图,大家都习惯了无图言X
用户2802329
2018/10/18
1.7K0
Android仿微信文章悬浮窗效果
Android轻量级APM性能监测方案
[GITHUB链接 Collie ](https://github.com/happylishang/Collie)
看书的小蜗牛
2020/09/16
3.9K0
我一行代码都不写实现Toolbar!你却还在封装BaseActivity?
距离 上篇文章 的发表时间已经过去两个多月了,这两个月时间里我没写文章但一直在更新着我的 MVPArms 框架,让他逐渐朝着 可配置化集成框架 发展
用户2802329
2018/08/07
3480
Android退出应用程序方法总结[通俗易懂]
在Android开发中,我们运行了应用程序后,都需要退出应用的,那么该如何退出应用,又都有哪些实现方式呢?今天就为大家整理分享一些退出应用程序的方法,一起来看看吧!
全栈程序员站长
2022/09/09
4.4K0
关于Android大数据收集,埋点统计的详细讲解以及案例代码分析附github代码
关于Android大数据收集,埋点统计的详细讲解以及案例代码分析附github代码
全栈程序员站长
2022/08/30
6190
相关推荐
判断前台 Activity 是否属于本进程
更多 >
LV.2
中国平安架构师
目录
  • 引言
  • I 、添加右滑返回手势
  • II、QMUI导致右滑返回没有生效的解决方法
    • 2.1 UINavigationController (QMUI)进行控制右滑返回
    • 2.2 解决方法
    • 2.3 动态添加方法
  • III、自定义导航条的rightBarButtonItem
  • see also
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档