携手创作,共同生长!这是我参与「日新方案 8 月更文应战」的第18天,点击检查活动概况
导言
原理:利用体系的回来手势interactivePopGestureRecognizer进行完成
运用场景: 回来按钮有点小,欠好触发回来时,可凭借右滑回来来提高用户体验
I 增加右滑回来手势
1.1 基于大局的UINavigationController基类完成
若项目有大局的UINavigationController基类,给页面增加右滑回来手势
@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;
}
1.2 办法交换(引荐)
往UIViewController 增加forceEnableInteractivePopGestureRecognizer办法将手势回来强制加回来
@implementation UIViewController (ERPPresent13)
+ (void)load {
[self addMethod:self.class method:@selector(forceEnableInteractivePopGestureRecognizer) method:@selector(kunnan_forceEnableInteractivePopGestureRecognizer)];
}
- (BOOL)kunnan_forceEnableInteractivePopGestureRecognizer {
return YES;
}
II QMUI导致右滑回来没有生效的处理办法
先来看看QMUI怎么完成完成右滑回来?
2.1 问题分析
QMUI运用分类UINavigationController (QMUI)
方式进行操控右滑回来,具体核心代码如下
- 重写viewDidLoad设置右滑回来手势的署理为本身
ExtendImplementationOfVoidMethodWithoutArguments([UINavigationController class], @selector(viewDidLoad), ^(UINavigationController *selfObject) {
selfObject.qmui_interactivePopGestureRecognizerDelegate = selfObject.interactivePopGestureRecognizer.delegate;
selfObject.interactivePopGestureRecognizer.delegate = (id<UIGestureRecognizerDelegate>)selfObject;
});
- gestureRecognizerShouldBegin
这个办法是在手势即将激活前调用:回来YES答应右滑手势的激活,回来NO不答应右滑手势的激活
- (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;
}
- iOS 13.4 开端会优先问询
shouldReceiveEvent
办法,只有回来 YES 后才会持续后续的逻辑
- (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
进行断定是否回来。
- (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
按钮
- (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 动态增加办法
运用场景:
- 在音讯发送和音讯转发时会用到动态增加办法
- 大局操控回来手势
下面的+addMethod
办法有三个参数,第一个参数是要增加办法的类,第二个参数是办法的SEL,第三个参数则是提供办法完成的SEL。
运用
class_getInstanceMethod()
和method_getImplementation()
获取相应SEL。下方的IMP其实便是Implementation的办法缩写,获取到相应的办法完成后,然后再调用class_addMethod()办法将IMP与SEL进行绑定即可。
/**
往类上增加新的办法与其完成
@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办法将手势回来强制加回来
@implementation UIViewController (ERPPresent13)
+ (void)load {
[self addMethod:self.class method:@selector(forceEnableInteractivePopGestureRecognizer) method:@selector(kunnan_forceEnableInteractivePopGestureRecognizer)];
}
- (BOOL)kunnan_forceEnableInteractivePopGestureRecognizer {
return YES;
}
III 相关知识点
3.1 WKWebView完成手势左滑回来上一级
// UI署理
_webView.UIDelegate = self;
// 导航署理
_webView.navigationDelegate = self;
// 是否答应手势左滑回来上一级, 相似导航操控的左滑回来
_webView.allowsBackForwardNavigationGestures = YES;
//可回来的页面列表, 存储已翻开过的网页
WKBackForwardList * backForwardList = [_webView backForwardList];
完好初始化代码
- (WKWebView *)webView{
if(_webView == nil){
//创立网页装备对象
WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
// 创立设置对象
WKPreferences *preference = [[WKPreferences alloc]init];
//最小字体大小 当将javaScriptEnabled属性设置为NO时,可以看到显着的效果
preference.minimumFontSize = 0;
//设置是否支撑javaScript 默许是支撑的
preference.javaScriptEnabled = YES;
// 在iOS上默许为NO,表示是否答应不通过用户交互由javaScript自动翻开窗口
preference.javaScriptCanOpenWindowsAutomatically = YES;
config.preferences = preference;
// 是运用h5的视频播放器在线播放, 仍是运用原生播放器全屏播放
config.allowsInlineMediaPlayback = YES;
//设置视频是否需求用户手动播放 设置为NO则会答应自动播放
config.requiresUserActionForMediaPlayback = YES;
//设置是否答应画中画技术 在特定设备上有用
config.allowsPictureInPictureMediaPlayback = YES;
//设置恳求的User-Agent信息中使用程序称号 iOS9后可用
config.applicationNameForUserAgent = @"ChinaDailyForiPad";
//自定义的WKScriptMessageHandler 是为了处理内存不开释的问题
WeakWebViewScriptMessageDelegate *weakScriptMessageDelegate = [[WeakWebViewScriptMessageDelegate alloc] initWithDelegate:self];
//这个类主要用来做native与JavaScript的交互办理
WKUserContentController * wkUController = [[WKUserContentController alloc] init];
//注册一个name为jsToOcNoPrams的js办法 设置处理接收JS办法的对象
[wkUController addScriptMessageHandler:weakScriptMessageDelegate name:@"jsToOcNoPrams"];
[wkUController addScriptMessageHandler:weakScriptMessageDelegate name:@"jsToOcWithPrams"];
config.userContentController = wkUController;
//以下代码适配文本大小
NSString *jSString = @"var meta = document.createElement('meta'); meta.setAttribute('name', 'viewport'); meta.setAttribute('content', 'width=device-width'); document.getElementsByTagName('head')[0].appendChild(meta);";
//用于进行JavaScript注入
WKUserScript *wkUScript = [[WKUserScript alloc] initWithSource:jSString injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES];
[config.userContentController addUserScript:wkUScript];
_webView = [[WKWebView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT) configuration:config];
// UI署理
_webView.UIDelegate = self;
// 导航署理
_webView.navigationDelegate = self;
// 是否答应手势左滑回来上一级, 相似导航操控的左滑回来
_webView.allowsBackForwardNavigationGestures = YES;
//可回来的页面列表, 存储已翻开过的网页
WKBackForwardList * backForwardList = [_webView backForwardList];
NSString *path = [[NSBundle mainBundle] pathForResource:k_localHtml4csdn ofType:nil];
NSString *htmlString = [[NSString alloc]initWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
[_webView loadHTMLString:htmlString baseURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]]];
}
return _webView;
}
3.2 自定义导航条的rightBarButtonItem
自定义导航条的rightBarButtonItem,选用initWithCustomView:rightBtn
设置rightBtn.frame
,让文字更大,更简单点击
kunnan.blog.csdn.net/article/det…
-(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、属性相关
kunnan.blog.csdn.net/article/det…