解决 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俱乐部,入坑苹果开发。
为了方便开发,在自己笔记本上装了黑苹果。配置开发环境都花了很多时间,有空分享一下自己装黑苹果的教程,给需要的人一些帮助吧

© Krist 2016 - 2024

|