iOS webview,WKWebView长按弹出框UIMenuController添加自定义功能
2016-10-27 16:59
417 查看
-先说下背景,`UIMenuController`类基于<UIKit>框架下,是iOS3.0之后发布的,它是一个长按呼出框,自带有复制、剪切、粘贴、全选、删除等等功能。文档里面定义如下图
![](http://img.blog.csdn.net/20161027145343734?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
****本次要实现的功能是 在加载了HTML字符串的UIWebView中实现自定义长按呼出框。
1.默认情况下,UITextFiled、UITextView、UIWebView这三个类及其子类都有自带的长按弹出UIMenuController功能,所有除了这三个以外,有需求的需要自己添加手势实现,实现方法与本文谈到的大同小异。
2.要使当前页面成为第一响应者。
3.屏蔽系统自带的弹出功能
*********下面开始
>首先创建UIMenuController,可以在需要实现的webview的构造方法里面创建代码如下:(此处我根据需求将UIWebView需要加载的内容由初始化赋值,并在调用属性setter方法的时候加载出来)
>注意要弹出UIMenuController必须完成三个步骤
1.在UIWebView中调用becomeFirstResponder方法。
2.在UIWebView中重写父类方法canBecomeFirstResponder并且 return Yes。
3.在UIWebView中重写canPerformAction:withSender:方法,来筛选出需要响应的item
第三点实现代码如下:
//指定menu响应事件屏蔽系统自带响应事件
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
if (action ==@selector(copy:) ||
action == @selector(selectAll:) ||
action == @selector(logSelectedText:)) {
returnYES;
}
returnNO;
}
>截止此处,就可以看到弹出的UIMenuController了,效果图如下:
![](http://img.blog.csdn.net/20161027160033635?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
>那么现在还存在俩个问题
1.赋值和全选都出现了俩次,且他们都是有效的。
2.打印选中文字还没实现,也没找到API直接获取这个选中文字的。
>针对问题1 是因为系统自带的和我们自定义都筛选出来了,解决办法是可以在我们开始的UIMenuController生成的地方删除这俩个重复的UIMenuItem.
那么此处涉及到它会显示"copy" "cut"俩个英文。如果支持中文需要到工程中配置一下Project->Info->Localizations里面找到Chinese(simplified)并添加。
此处注意这样添加后显示的语言是根据手机或者模拟器设置的语言而定的。 配置如下:
![](http://img.blog.csdn.net/20161027163914455?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
>针对问题2 首先需要讲一下 cut: copy:等系统自带的方法,这些方法通通放在了UIResponderStandardEditActions协议中.具体有以下方法:
然后就是实现我们自定义的打印出选中文字的方法。我找了一下,并有找到UIMenuController有直接的属性获取选中的文字,固寻求其他解决途径。
有俩种解决方法仅供参考:
1.利用js代码直接获取UIWebView中被选中的文字
2.利用UIMenuController带的赋值方法将内容赋值到粘贴板,再从粘贴板获得所需内容
----------------17.11.6更新-----------------
遇到俩三个同学问我适配WKWebView之后上面的代码不能很好的支持。之前帮一个同学解决了又忘记了,今天又被问到,感谢@灯红酒绿映不出的落寞 提供的思路。
因为WKWeb用相同的方法写会出现一个问题就是不能屏蔽系统的一些方法。
解决办法是把UIMenuController提出来写到ViewController层,所以在这儿需要实现一个方法就是禁止对象取消第一响应
这样写功能是实现了,但是存在一个bug.理论上一个viewcontroller被pop出navigationController的栈之后会释放,但是这个对象似乎没有完全消失,因为我们写了这个对象禁止取消第一响应,其他的对象就不能再响应了。有时候这个bug也会表现为在定义着不同的UIMenuController的不同视图中表现为同一个。所以我们在视图消失的时候应该允许他取消第一响应,而视图存在的时候不行。
没有懂的同学把这个判断取消就明白了。我在UIWebView中允许出现“拷贝,全选,打印选中文字”,在WK中允许出现“自定义复制,添加笔记”。
结合Demo,第一次用UIWebView正常,用了WK没加上面判断之后再看UIWebView异常
![](http://img.blog.csdn.net/20171106161024440?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveG15MDAxMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
![](http://img.blog.csdn.net/20171106161045996?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveG15MDAxMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
Github上面已经更新。
----------------18.1.9更新-----------------
有小伙伴问到使用WKWebView用我上面的方法做出来没有全选功能,想要添加一个全选功能。
其实很简单
我试过直接屏蔽函数中添加不屏蔽selectedAll:,但是会造成程序崩溃,有兴趣的可以试试写一个WKWebview的子类屏蔽看看。
1.添加一个UIMenuItem叫做“全选”。
2.在屏蔽函数中打开我们自定义的全选。(注意方法名不要和系统方法名冲突)
3.实现自定义全选。利用[WKWebView selectAll:]函数,注意实现之后把允许视图取消第一响应的判定改一下,不然会出现全选异能取消的BUG.
遗留了一个bug就是我们使用过一次全选功能之后,以后再打开UIMenuController有几个系统方法就不能屏蔽了(因为之后不会再调用[self canResignFirstResponder]方法,现在使用Wk的时候系统方法这块确实API有一定的问题,很多实现都是屏蔽UIMenuController采用UIAlertController来替代),希望有解决办法的小伙可以不吝赐教,谢谢!
***以上
(欢迎随手给一颗星星哦~)本篇博客Demo地址https://github.com/xmy0010/DemoForCSDN
本人邮箱18144200589@163.com欢迎小伙伴一起讨论,学习,进步。
****本次要实现的功能是 在加载了HTML字符串的UIWebView中实现自定义长按呼出框。
1.默认情况下,UITextFiled、UITextView、UIWebView这三个类及其子类都有自带的长按弹出UIMenuController功能,所有除了这三个以外,有需求的需要自己添加手势实现,实现方法与本文谈到的大同小异。
2.要使当前页面成为第一响应者。
3.屏蔽系统自带的弹出功能
*********下面开始
>首先创建UIMenuController,可以在需要实现的webview的构造方法里面创建代码如下:(此处我根据需求将UIWebView需要加载的内容由初始化赋值,并在调用属性setter方法的时候加载出来)
- (instancetype)initWithFrame:(CGRect)frame content:(NSString *)content { self = [super initWithFrame:frame]; if (self) { [self becomeFirstResponder]; [self createMenu]; self.content = content; } return self; } //构建UIMenuController - (void)createMenu { UIMenuController *menu = [UIMenuController sharedMenuController]; UIMenuItem *item0 = [[UIMenuItem alloc] initWithTitle:@"复制" action:@selector(copy:)]; UIMenuItem *item1 = [[UIMenuItem alloc] initWithTitle:@"全选" action:@selector(selectAll:)]; UIMenuItem *item2 = [[UIMenuItem alloc] initWithTitle:@"打印选中文字" action:@selector(logSelectedText:)]; [menu setMenuItems:@[ item0, item1, item2]]; } //内容的setter方法里面加载 - (void)setContent:(NSString *)content { _content = content; [self loadHTMLString:content baseURL:nil]; }
>注意要弹出UIMenuController必须完成三个步骤
1.在UIWebView中调用becomeFirstResponder方法。
2.在UIWebView中重写父类方法canBecomeFirstResponder并且 return Yes。
3.在UIWebView中重写canPerformAction:withSender:方法,来筛选出需要响应的item
第三点实现代码如下:
//指定menu响应事件屏蔽系统自带响应事件
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
if (action ==@selector(copy:) ||
action == @selector(selectAll:) ||
action == @selector(logSelectedText:)) {
returnYES;
}
returnNO;
}
>截止此处,就可以看到弹出的UIMenuController了,效果图如下:
>那么现在还存在俩个问题
1.赋值和全选都出现了俩次,且他们都是有效的。
2.打印选中文字还没实现,也没找到API直接获取这个选中文字的。
>针对问题1 是因为系统自带的和我们自定义都筛选出来了,解决办法是可以在我们开始的UIMenuController生成的地方删除这俩个重复的UIMenuItem.
那么此处涉及到它会显示"copy" "cut"俩个英文。如果支持中文需要到工程中配置一下Project->Info->Localizations里面找到Chinese(simplified)并添加。
此处注意这样添加后显示的语言是根据手机或者模拟器设置的语言而定的。 配置如下:
>针对问题2 首先需要讲一下 cut: copy:等系统自带的方法,这些方法通通放在了UIResponderStandardEditActions协议中.具体有以下方法:
// @protocol UIResponderStandardEditActions <NSObject> // @optional // - (void)cut:(nullable id)sender NS_AVAILABLE_IOS(3_0); //剪切 // - (void)copy:(nullable id)sender NS_AVAILABLE_IOS(3_0); //复制 // - (void)paste:(nullable id)sender NS_AVAILABLE_IOS(3_0); //粘贴 // - (void)select:(nullable id)sender NS_AVAILABLE_IOS(3_0); //选择 // - (void)selectAll:(nullable id)sender NS_AVAILABLE_IOS(3_0); //全选 // - (void)delete:(nullable id)sender NS_AVAILABLE_IOS(3_2); //删除 // - (void)makeTextWritingDirectionLeftToRight:(nullable id)sender NS_AVAILABLE_IOS(5_0); //改变书写模式为从左向右按钮触发 // - (void)makeTextWritingDirectionRightToLeft:(nullable id)sender NS_AVAILABLE_IOS(5_0); //改变书写模式为从右向左按钮触发 // // //以下方法调用会导致程序崩溃 具体原因再研究 // - (void)toggleBoldface:(nullable id)sender NS_AVAILABLE_IOS(6_0); // - (void)toggleItalics:(nullable id)sender NS_AVAILABLE_IOS(6_0); // - (void)toggleUnderline:(nullable id)sender NS_AVAILABLE_IOS(6_0); // // - (void)increaseSize:(nullable id)sender NS_AVAILABLE_IOS(7_0); // - (void)decreaseSize:(nullable id)sender NS_AVAILABLE_IOS(7_0); // // @end
然后就是实现我们自定义的打印出选中文字的方法。我找了一下,并有找到UIMenuController有直接的属性获取选中的文字,固寻求其他解决途径。
有俩种解决方法仅供参考:
1.利用js代码直接获取UIWebView中被选中的文字
//UIWebView自带获取选中文字的方法 - (NSString *)getSelectedText { return [self stringByEvaluatingJavaScriptFromString:@"window.getSelection().toString()"]; }
2.利用UIMenuController带的赋值方法将内容赋值到粘贴板,再从粘贴板获得所需内容
//先复制到粘贴板 再打印粘贴板上的内容 [self copy:menu]; NSLog(@"选中的文字为:%@", [UIPasteboard generalPasteboard].string);
----------------17.11.6更新-----------------
遇到俩三个同学问我适配WKWebView之后上面的代码不能很好的支持。之前帮一个同学解决了又忘记了,今天又被问到,感谢@灯红酒绿映不出的落寞 提供的思路。
因为WKWeb用相同的方法写会出现一个问题就是不能屏蔽系统的一些方法。
canPerformAction: withSender:
解决办法是把UIMenuController提出来写到ViewController层,所以在这儿需要实现一个方法就是禁止对象取消第一响应
- (BOOL)canBecomeFirstResponder { return YES; } - (BOOL)canResignFirstResponder { return NO; }
这样写功能是实现了,但是存在一个bug.理论上一个viewcontroller被pop出navigationController的栈之后会释放,但是这个对象似乎没有完全消失,因为我们写了这个对象禁止取消第一响应,其他的对象就不能再响应了。有时候这个bug也会表现为在定义着不同的UIMenuController的不同视图中表现为同一个。所以我们在视图消失的时候应该允许他取消第一响应,而视图存在的时候不行。
- (BOOL)canBecomeFirstResponder { return YES; } - (BOOL)canResignFirstResponder { if (_dismissSelf) { return YES; } return NO; }
没有懂的同学把这个判断取消就明白了。我在UIWebView中允许出现“拷贝,全选,打印选中文字”,在WK中允许出现“自定义复制,添加笔记”。
结合Demo,第一次用UIWebView正常,用了WK没加上面判断之后再看UIWebView异常
Github上面已经更新。
----------------18.1.9更新-----------------
有小伙伴问到使用WKWebView用我上面的方法做出来没有全选功能,想要添加一个全选功能。
其实很简单
我试过直接屏蔽函数中添加不屏蔽selectedAll:,但是会造成程序崩溃,有兴趣的可以试试写一个WKWebview的子类屏蔽看看。
canPerformAction: withSender:另一种思路就是按照之前添加自定义功能的方法添加一个方法叫做“全选”。
1.添加一个UIMenuItem叫做“全选”。
2.在屏蔽函数中打开我们自定义的全选。(注意方法名不要和系统方法名冲突)
3.实现自定义全选。利用[WKWebView selectAll:]函数,注意实现之后把允许视图取消第一响应的判定改一下,不然会出现全选异能取消的BUG.
遗留了一个bug就是我们使用过一次全选功能之后,以后再打开UIMenuController有几个系统方法就不能屏蔽了(因为之后不会再调用[self canResignFirstResponder]方法,现在使用Wk的时候系统方法这块确实API有一定的问题,很多实现都是屏蔽UIMenuController采用UIAlertController来替代),希望有解决办法的小伙可以不吝赐教,谢谢!
***以上
(欢迎随手给一颗星星哦~)本篇博客Demo地址https://github.com/xmy0010/DemoForCSDN
本人邮箱18144200589@163.com欢迎小伙伴一起讨论,学习,进步。
相关文章推荐
- iOS 使用WKWebView加载h5页面无法调用拨打电话功能
- iOS 添加WKWebView导致控制器无法释放的问题
- 浅谈iOS中的WKWebView添加cookie
- iOS WKWebView添加网页加载进度条(转)
- iOS WKWebView添加网页加载进度条
- IOS WKWebView初级使用 以及WKWebView进度条的添加
- iOS WKWebView添加进度条02
- IOS平台:PhoneGap添加新类(javaScript与webView交互)----功能扩展
- Android自定义View之自定义EditText(添加删除功能)
- iOS项目开发小技巧 (三) --UITableView实现Cell左划删除等自定义功能
- iOS - 自定义alertView,继承自UIView,可以添加子视图,标题图片+文字
- iOS 混合应用的关键点分析 - 仿 Android 平台 WebView 可注入本地对象方法的功能实现要点
- cocos2dx添加android的webView cocos2d-x在iOS Android添加WebView
- iOS 使用 WKWebView 无法截获上、下手势的问题解决
- iOS 8 WKWebView
- ios之wkwebview与UIwebview的对比
- 给CHtmlEditView添加自定义拖拽功能IDropTargetpdwEffectDROPEFFECT_COPY
- iOS8中webview添加定位功能
- iOS 新浪微博客户端Demo实践之(八) 添加图片放大,slide view和定位功能
- IOS 为UILabel和UIImageView添加长按复制功能