WKWebView之长按手势_wkwebview touch-程序员宅基地

技术标签: 手势  WKWebView  长按手势  

WKWebView之长按手势


PAWebView
PAWebView 之 cookie 管理与同步;
PAWebView 之长按手势;
PAWebView 之POST请求;

一、引言

   在hybird app 里,长按手势的运用非常广泛,特别是DOM的运用与native和JS交互的实现,使得Navitve对HTML的操作无所不能。如查看、屏蔽、替换、复制、下载、识别二维码和分享等功能都可以轻松实现,那么长按手势更是可以实现让用户便捷的一些功能。

二、WKWebView长按手势

1. WebView触摸事件

   绝大多WebView层的触摸事件暂时还不能由Native直接拦截更改,目前Native可以监听长按、点击等一些手势状态,但是如果需要禁止或改变这些事件或属性,我们可以通过向H5注入JS代码来实现,iOS WebKit 框架下的CSS扩展也可以实现部分功能

2.关闭网页的长按手势

   利用WebKit CSS 扩展 webkitTouchCallout属性实现。
document.documentElement.style.webkitTouchCallout=’none’;

错误用法:
   一些开发者在webViewDidFinishLoad 代理中实现该方法。实际上,经过测试,这种调用方法不能完全禁止WebView端的长按手势,估计是网页加载过慢时方法注入延时导致WebView端长按依然有效。


- (void)webViewDidFinishLoad:(UIWebView *)webView {
    // Disable callout
    [webView stringByEvaluatingJavaScriptFromString:@"document.documentElement.style.webkitTouchCallout='none';"];

正确用法:
   在初始化WebView时使用WKUserContentController对象注入禁止长按的方法。


NSMutableString *javascript = [NSMutableString string];
[javascript appendString:@"document.documentElement.style.webkitTouchCallout='none';"];//禁止长按
WKUserScript *noneSelectScript = [[WKUserScript alloc] initWithSource:javascript injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES];
[_config.userContentController addUserScript:noneSelectScript];

3.WebView添加手势
  • webview添加事件

UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(startLongPress:)];
longPress.delegate = self;

longPress.minimumPressDuration = 0.4f;
longPress.numberOfTouchesRequired = 1;
longPress.cancelsTouchesInView = YES;
[self addGestureRecognizer:longPress];

  • 实现UILongPressGestureRecognizer代理,精确处理手势动作

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
    NSLog(@"%@",otherGestureRecognizer.class);

    if ([otherGestureRecognizer isKindOfClass:[UILongPressGestureRecognizer class]]) {
        //只有当手势为长按手势时反馈,飞长按手势将阻止。
        return YES;
    }else{
        return NO;
    }
}

  • 长按反馈

- (void)startLongPress:(UILongPressGestureRecognizer *)pressSender
{
    if(pressSender.state == UIGestureRecognizerStateBegan){

       //实现相关功能
        [self detectInWebView:pressSender];
        NSLog(@"1. 开始长按手势");

    }else if(pressSender.state == UIGestureRecognizerStateEnded){

        //可以添加你长按手势执行的方法,不过是在手指松开后执行
        NSLog(@"2. 结束长按手势");

    }else if(pressSender.state == UIGestureRecognizerStateChanged){

        //在手指点下去一直不松开的状态执行
        NSLog(@"3. 长按手势改变");
    }
}

4.解决长按结束时a对应URL超链接触发跳转问题

   查阅了很多国内技术论坛资料,这个问题普遍都困扰着开发者。我研究了一下系统自带的长按手势的功能,当长按触发时,WebView 的手势响应事件被全部终止,然后弹出UIMenuController视图,UC也是类似的处理。目前不清楚怎么实现,知道的伙伴交流一下。但是可以使用其他方法来代替。

方法一:
   以弹出的视图作为长按触发成功的标志,视图弹出,长按触发,然后在WKWebView的代理方法 decidePolicyForNavigationAction 里拦截网页跳转;视图消失,长按完毕。方法虽笨,但是还是很实用,目前的很多开发者都采用这种方式实现。


- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:
(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
{

    if (_longpress) {
        _longpress = NO;
        decisionHandler(WKNavigationActionPolicyCancel);
        return;
    }
}

方法二
   借助系统自带的长按响应机制忽略单击事件。去掉document.documentElement.style.webkitTouchCallout=’none’;设置。
移除UIMenuController清除系统的长按响应形式。弹出我们自定义的弹框形式。

移除视图的方法


for (UIView* subview in self.webViewWK.scrollView.subviews) 
{         
   if ([subview isKindOfClass:NSClassFromString(@"WKContentViewMinusAccessoryView")])         
  {             
       for (UIGestureRecognizer* longPress in subview.gestureRecognizers) 
     {                     
         [subview removeGestureRecognizer:longPress];                          
       }             
    }        
}    

5.抓取/更改网页元素属性

   抓取H5主要使用了WKWebView的JS代码注入和DOM的H5文件操作来实现。
   JS代码注入方法。届时除了了解JS代码注入的实现,还需要了解JavaScript/jQuery,HTML,DOM的相关知识。

相关教程:
JS:http://www.w3school.com.cn/js/js_library_jquery.asp
HTML:http://www.w3school.com.cn/html5/index.asp
DOM:http://www.w3school.com.cn/htmldom/dom_intro.asp

WKWebView框架注入代码API


[self evaluateJavaScript:JSFunction completionHandler:^(id _Nullable href, NSError * _Nullable error)
{}];

相关JS方法


1.获取点击位置的url
function JSSearchHref(x,y) {
    
                        var e = document.elementFromPoint(x, y);
                        while(e){
                            if(e.href){
                            return e.href;
                        }
                        e = e.parentElement;
                        }
                        return e.href;
                  }
2.获取标题

function JSSearchText(x,y) {
    
                  return document.elementFromPoint(x, y).innerText;
                    }
3.获取图片

function JSSearchImage(x,y) {
    
                        return document.elementFromPoint(x, y).src;
                    }
4.获取HTML所有的图片

function JSSearchAllImage(){
    
         var img = [];
         for(var i=0;i<$('img').length;i++){
              if(parseInt($('img').eq(i).css('width'))>60){ 
                 //获取所有符合放大要求的图片,将图片路径(src)获取
                 img[i] = $('img').eq(i).attr('src');
               }
             }
         var img_info = {};
         img_info.list = img; //保存所有图片的url
         return img;
}
5.获取web page的宽
document.getElementById('content').offsetWidth
6.获取web page的长
document.getElementById('content').offsetHeight
等等。。

JS注入使用例子



/** 获取HTML所有的图片 */
NSString* const JSSearchAllImageFromHtml =
           @"function JSSearchAllImage(){\
                var img = [];\
                for(var i=0;i<$('img').length;i++){\
                   if(parseInt($('img').eq(i).css('width'))>60){ \
                       //获取所有符合放大要求的图片,将图片路径(src)获取
                       img[i] = $('img').eq(i).attr('src');\
                     }\
               }\
               var img_info = {};\
               img_info.list = img;\ //保存所有图片的url
               return img;\
           };

//注入JS方法
NSString *hrefJS = JSSearchAllImageFromHtml;
[self evaluateJavaScript:hrefJS completionHandler:nil];

//调用JS方法
NSString *hrefFunc = [NSString stringWithFormat:@"JSSearchAllImage();"];
[self evaluateJavaScript:hrefFunc completionHandler:^(id _Nullable image, NSError * _Nullable error)
{
      NSArray *imageArray = [self sortImageFromArray:image];
      NSLog(@"%@",imageArray);
}];


6.具体功能的实现

   PAWebView里面具体实现了该功能。具体代码和功能的实现请查看 github :https://github.com/llyouss/PAWeView

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/llyouss/article/details/79389276

智能推荐

永久解决pycharm中一直在python console中调试问题_pycharm python comsole 问题-程序员宅基地

文章浏览阅读3.5k次,点赞3次,收藏3次。最近使用pycharm调试程序时非常的烦,每次都默认的在python console中进行调试,都需要手动的到菜单栏中的Run----去配置,将在python console勾选为空,然而问题来了,等到调试下一个程序时又会出现同样的问题,查询csdn发现还没有解决方案,就自己整了下,竟然成功了,分享下首先在菜单栏中找到Run------> Edit configurations..._pycharm python comsole 问题

一步搞懂镜像文件_文件镜像方法不同镜像出来的文件相同吗-程序员宅基地

文章浏览阅读1.1k次。常见的镜像文件格式主要有:.iso、.bin、.nrg、.vcd、.cif、.fcd、.img、.ccd、.c2d、.dfi、.tao、.dao和.cue 等。每种刻录软件支持的镜像文件格式都各不相同,比如说Nero支持.nrg、.iso和.cue,Easy CD Creator支持.iso、.cif,CloneCD支持.ccd等。在虚拟光驱中我们需要加入镜像文件(相当于一个游戏光盘),才能够顺利完成游戏的安装,完成安装之后再载入这个镜像就可以进入游戏当中了。标准 ISO 镜像文件 *.iso。_文件镜像方法不同镜像出来的文件相同吗

HDU 3486 Interviewe (RMQ+暴力,3级)_hdoj3486-程序员宅基地

文章浏览阅读1.1k次。F - IntervieweCrawling in process...Crawling failedTime Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64uSubmitStatus Appoint description:System Crawler (2_hdoj3486

运算符重载_complex_add里的_是干什么的-程序员宅基地

文章浏览阅读737次。1什么是运算符重载所谓重载,就是重新赋予新的含义。函数重载就是对一个已有的函数赋予新的含义,使之实现新功能。运算符也可以重载。实际上,我们已经在不知不觉之中使用了运算符重载。现在要讨论的问题是: 用户能否根据自己的需要对C++已提供的运算符进行重载,赋予它们新的含义,使之一名多用。譬如,能否用“+”号进行两个复数的相加。在C++中不能在程序中直接用运算符“+”对复数进行相加运算。用户必_complex_add里的_是干什么的

linux系统怎么移动窗口,linux – 如何使用wmctrl在窗口外移动窗口-程序员宅基地

文章浏览阅读1k次。我试图以编程方式移动一个窗口,使其部分在屏幕上.例如,单击VLC标题栏并拖动它以便只有一半窗口可见,效果很好.当我输出wmctrl -lG的结果时,这很好用:0x04a00011 0 -293 138 600 420 HEVM002 VLC media player然而,当我然后将它移回屏幕并尝试复制其位置时,它不起作用并将窗口剪切到远端:wmctrl -r "VLC media play..._wmctrl

Oracle 补丁体系(PSR/PSU/CPU) 及 opatch 工具 介绍_oracle cpu和psu区别-程序员宅基地

文章浏览阅读5.2k次。原文:http://blog.csdn.net/tianlesoftware/article/details/5809526一. CPU(Critical Patch Update) 一个CPU内包含了对多个安全漏洞的修复,并且也包括相应必需的非安全漏洞的补丁。CPU是累积型的,只要安装最新发布的CPU即可,其中包括之前发布的所有CPU的内容。事实上,在CPU之前的安全漏洞修改除_oracle cpu和psu区别

随便推点

用ifconfig命令,显示结果只有lo,没有eth0_银河麒麟ifconfig只有lo和sit0-程序员宅基地

文章浏览阅读9k次。解决1. 输入ifconfig -a命令,可以看到eth0和lo。2. 进入/etc/sysconfig/network-scripts 目录,发现有ifcfg-eth0,即网卡(驱动)存在但未启用。3. 输入ifconfig eth0 up,启用网卡。此时用ifconfig,只能看到inet6的地址,没有ip4. vi /etc/sysconfig/network-scrip_银河麒麟ifconfig只有lo和sit0

微信多开软件工具及批处理文件教程_微信多开批处理文件-程序员宅基地

文章浏览阅读487次,点赞13次,收藏9次。微信多开小工具,通过批处理文件用于实现微信多开的功能。_微信多开批处理文件

vulnhub DC7 靶场练习_dc7靶场-程序员宅基地

文章浏览阅读1.6k次,点赞2次,收藏2次。前言这次练习的靶机是vulnhub平台下的DC系列靶机第7台,下载地址为https://www.vulnhub.com/entry/dc-7,356/。挑战该靶机的最终目的是获取root权限,然后读取唯一的flag。这台靶机中用暴力破解成功的概率非常小,我们需要开阔思路,寻找非技术上的方法。虚拟机配置这次采用的网络连接模式依然是NAT模式,为了避免扫描到其他物理主机。在导入虚拟机后,右击DC-6靶机,然后选中配置。依次点击网络配置->NAT模式->高级->生成,然后确认即可。收集_dc7靶场

二本学渣考研失败,移动APP开发框架盘点,含小米、腾讯、阿里_移动开发框架 公司-程序员宅基地

文章浏览阅读685次,点赞3次,收藏6次。前言Hi~,我是 2020 届物联网专业毕业生,现就读于杭州。谨以此文来记录我的秋招以及入门前端以来的学习历程,如有错误,希望大家能及时提出!面试情况前前后后一共面试了 14 家公司的前端岗,按城市划分为:北京:小米,京东,美团,百度,去哪儿杭州:阿里,网易,微店,字节跳动上海:七牛云,哈啰出行深圳:腾讯,富途,乐信历时4个月,最终收获了 小米、京东、微店、字节跳动 的offer展望未来操作系统移动操作系统的演变过程,从按键交互的塞班功能机到触摸屏交互的Android/IOS智_移动开发框架 公司

Android FragmentTabHost-程序员宅基地

文章浏览阅读930次。TabActivity例子()_android fragmenttabhost

清华大学施路平:发展人工通用智能最好的时机到了!-程序员宅基地

文章浏览阅读445次。来源:学术头条今年8月,一辆来自清华的无人驾驶自行车登上了Nature的封面。这是中国的人工智能芯片首次登上Nature,在全球引发热议。这辆自行车不仅可以平衡自身,还..._类脑计算大会,施路平

推荐文章

热门文章

相关标签