系统返回方法 默认是pop回上一个界面,实际情况中并不总是要返回上一个界面,比如用户注册登录之后不想再返回到原来注册登录界面,比如webview里面不停的forword,那么这时候系统返回按钮直接就退出了webview界面,当然我们可以通过设置leftBarButttonItem或者presentViewController的方式,
这里只是一个既能保持系统原有方法的前提下,最小化改动,最大化依赖系统控件
思路是通过runtime method swizzling 拦截点击系统返回事件 ,通过判断UIGestureRecognizerDelegate的手势拦截右滑返回事件
//Returns a Boolean value indicating whether the navigation bar should pop an item.
- (BOOL)navigationBar:(UINavigationBar *)navigationBar
shouldPopItem:(UINavigationItem *)item;
复制代码
代码如下
1.创建UINavigationController分类.h
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface UINavigationController (navigationPopBack)
@end
NS_ASSUME_NONNULL_END
复制代码
#import "UIViewController+BackButtonEvent.h"
#import "NSObject+theSwizzling.h"
#import "UINavigationController+navigationPopBack.h"
#import <objc/runtime.h>
static void * const interactivePopGestureDelegate = "interactivePopGestureDelegate";
@implementation UINavigationController (navigationPopBack)
+(void)load{
//页面进入就加载 区分父类 子类 分类 不覆盖其他类load的实现 initialize 懒加载不一定会实现
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[self methodSwizzlingWithOriginalSelector:@selector(navigationBar:shouldPopItem:) bySwizzlingedSelector:@selector(lsh_navigationBar:shouldPopItem:)];
});
}
-(void)viewDidLoad
{
[super viewDidLoad];
objc_setAssociatedObject(self,interactivePopGestureDelegate , self.interactivePopGestureRecognizer.delegate, OBJC_ASSOCIATION_ASSIGN);
self.interactivePopGestureRecognizer.delegate = (id<UIGestureRecognizerDelegate>)self;
}
- (BOOL)lsh_navigationBar:(UINavigationBar *)navigationBar
shouldPopItem:(UINavigationItem *)item{
UIViewController *vc =self.topViewController;
if (item != vc.navigationItem) {
return YES;
}
if ([vc conformsToProtocol:@protocol(BackButtonHandler)]&&[vc respondsToSelector:@selector(test_navigationShouldPopOnBackButton)]) {
if ([vc test_navigationShouldPopOnBackButton]) {
return [self lsh_navigationBar:navigationBar shouldPopItem:item];
}
else{
for (UIView *subview in [navigationBar subviews]) {
if (subview.alpha >0 && subview.alpha<1.0) {
[UIView animateWithDuration:.25 animations:^{
subview.alpha = 1;
}];
}
}
return NO;
}
}
else{
return [self lsh_navigationBar:navigationBar shouldPopItem:item];
}
return NO;
}
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{
if (gestureRecognizer == self.interactivePopGestureRecognizer) {
// 解决根视图侧滑导致push卡死的问题
if (self.viewControllers.count == 1) {
return NO;
}
// 当前视图不是根视图,执行popBack操作
UIViewController *vc = self.topViewController;
if([vc respondsToSelector:@selector(test_navigationShouldPopOnBackButton)]) {
return [vc test_navigationShouldPopOnBackButton];
}
id<UIGestureRecognizerDelegate> originDelegate = objc_getAssociatedObject(self, interactivePopGestureDelegate);
return [originDelegate gestureRecognizerShouldBegin:gestureRecognizer];
}
return YES;
}
@end
复制代码
UIViewController+BackButtonEvent 这个分类我之前没这个写过,代理直接在.h文件后实现,自己设置代理,自己引用代理?一般的写法是A文件设置代理,B文件调用A,B作为A的代理实现A的代理方法。而这里A文件设置代理,并作为自己的代理,只是没实现方法而已。
@protocol BackButtonHandler <NSObject>
-(BOOL)test_navigationShouldPopOnBackButton;
@end
@interface UIViewController (BackButtonEvent)<BackButtonHandler>
@end
复制代码
#import "UIViewController+BackButtonEvent.h"
@implementation UIViewController (BackButtonEvent)
@end
复制代码
NSObject+theSwizzling
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface NSObject (theSwizzling)
+(void)methodSwizzlingWithOriginalSelector:(SEL)originalSelector bySwizzlingedSelector:(SEL)swizzledSelector;
@end
复制代码
#import "NSObject+theSwizzling.h"
#import <objc/message.h>
@implementation NSObject (theSwizzling)
+(void)methodSwizzlingWithOriginalSelector:(SEL)originalSelector bySwizzlingedSelector:(SEL)swizzledSelector{
Class class = [self class];
Method originalMethod = class_getInstanceMethod(class, originalSelector);
Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
BOOL didAddMethod = class_addMethod(class, swizzledSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));
if (didAddMethod) {
class_replaceMethod(class, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
}
else{
method_exchangeImplementations(originalMethod, swizzledMethod);
}
}
@end
复制代码
使用方法
#import "UIViewController+BackButtonEvent.h"
#import "WebLSHViewController.h"
@interface WebLSHViewController ()
@end
@implementation WebLSHViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
-(BOOL)test_navigationShouldPopOnBackButton
{
NSLog(@"test_navigationShouldPopOnBackButton");
}
@end
复制代码
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END