解决 Swift4 添加长按事件 UILongPressGestureRecognizer 后重复响应的问题
date
Nov 9, 2018
slug
fix-swift4-long-press-event-double-response
status
Published
tags
iOS开发
summary
IOS开发入门,第一个APP就写了一个计算器,为了添加长按结果Label即可复制的功能,经过查询,发现系统自带的UIlabel控件默认不含长按响应,现在的情况是只能自行拓展添加UILabel控件的长按响应功能,经过一番搜索后在网上找到了拓展Uilabel类的解决方法
type
Post
- 本文所有代码均基于Swift4语言
IOS开发入门,第一个APP就写了一个计算器
为了添加长按结果Label即可复制的功能,经过查询,发现系统自带的UIlabel控件默认不含长按响应
现在的情况是只能自行拓展添加UILabel控件的长按响应功能,经过一番搜索后在网上找到了拓展Uilabel类的解决方法
经过调试后成功将代码跑到了我的计算器上,并且实现了长按弹出菜单复制的功能
可是在响应的时候出现了一个问题,如果我长按的手指不从label控件上拿开,这个复制菜单会持续的响应弹出,并不能做到一次长按只弹出一次菜单的效果
观察其响应代码,我觉得优化点可能在这里:
func setup() {
isUserInteractionEnabled = true
let guesture = UILongPressGestureRecognizer(target: self, action: #selector(clickLabel))
self.addGestureRecognizer(guesture)
}
func clickLabel() {
// 让其成为响应者
becomeFirstResponder()
// 拿出菜单控制器单例
let menu = UIMenuController.shared
// 创建一个复制的item
let copy = UIMenuItem(title: "复制", action: #selector(copyText))
// 将复制的item交给菜单控制器(菜单控制器其实可以接受多个操作)
menu.menuItems = [copy]
// 设置菜单控制器的点击区域为这个控件的bounds
menu.setTargetRect(bounds, in: self)
// 显示菜单控制器,默认是不可见状态
menu.setMenuVisible(true, animated: true)
}
果不其然,经过再次的搜索后(发现很多IOS开发都用的objectc来写的,对swift的相对来说少之又少),发现在进行弹出响应时候代码没有进行
是否是第一次响应
的判断,导致其持续长按会重复弹出菜单。网上的代码都是 ObjectC的 代码,好在 swift 对新手友好,改起来并不难。将判断代码加入后的程序如下:
func setup() {// 让其有交互能力,并添加一个长按手势
isUserInteractionEnabled = true
let guesture = UILongPressGestureRecognizer(target: self, action: #selector(clickLabel))
self.addGestureRecognizer(guesture)
}
func clickLabel(recognizer: UILongPressGestureRecognizer) {
if(recognizer.state == UIGestureRecognizer.State.began)//防止单次长按时重复响应
{
// 让其成为响应者
becomeFirstResponder()
// 拿出菜单控制器单例
let menu = UIMenuController.shared
// 创建一个复制的item
let copy = UIMenuItem(title: "复制", action: #selector(copyText))
// 将复制的item交给菜单控制器(菜单控制器其实可以接受多个操作)
menu.menuItems = [copy]
// 设置菜单控制器的点击区域为这个控件的bounds
menu.setTargetRect(bounds, in: self)
// 显示菜单控制器,默认是不可见状态
menu.setMenuVisible(true, animated: true)
}
}
其中,
UIGestureRecognizer.State.began
变量在首次弹出时候会为事件状态值,之后对于该次长按操作值都会变为UIGestureRecognizer.State.end
,在创建菜单之前对该变量进行判断,就可以控制单次长按的菜单刷新数量了。这样子,重复响应的问题就解决了。
最后,贴出UILabel控件长按弹出复制菜单的扩展类,在swift4的环境下可以直接使用。
@objcMembers
class CanCopyLabel: UILabel {//添加长按复制功能
override var canBecomeFirstResponder: Bool { return true }
override init(frame: CGRect) {// 代码创建控件的时候有效
super.init(frame: frame)
setup()
}
required init?(coder aDecoder: NSCoder) {// storyboard或xib创建控件的时候有效
super.init(coder: aDecoder)
setup()
}
func setup() {// 让其有交互能力,并添加一个长按手势
isUserInteractionEnabled = true
let guesture = UILongPressGestureRecognizer(target: self, action: #selector(clickLabel))
self.addGestureRecognizer(guesture)
}
func clickLabel(recognizer: UILongPressGestureRecognizer) {
if(recognizer.state == UIGestureRecognizer.State.began)//防止单次长按时重复响应
{
// 让其成为响应者
becomeFirstResponder()
// 拿出菜单控制器单例
let menu = UIMenuController.shared
// 创建一个复制的item
let copy = UIMenuItem(title: "复制", action: #selector(copyText))
// 将复制的item交给菜单控制器(菜单控制器其实可以接受多个操作)
menu.menuItems = [copy]
// 设置菜单控制器的点击区域为这个控件的bounds
menu.setTargetRect(bounds, in: self)
// 显示菜单控制器,默认是不可见状态
menu.setMenuVisible(true, animated: true)
}
}
func copyText() {
UIPasteboard.general.string = self.text
}
override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
if action == #selector(copyText) {
return true
} else {
return false
}
}
}
荣幸加入学校iOS俱乐部,入坑苹果开发。
为了方便开发,在自己笔记本上装了黑苹果。配置开发环境都花了很多时间,有空分享一下自己装黑苹果的教程,给需要的人一些帮助吧