iOS开发,UILabel的长按复制文本功能

487 阅读1分钟

大家好,这里是程序员阿山哥🤓今天给大家分享通过UIMenuController来实现UILabel的长按复制文本功能。

开发环境
Xcode 13.2.1
iOS 15.2

image.png

import UIKit

class MenuLabel: UILabel {

    override func awakeFromNib() {
        super.awakeFromNib()
      // 要打开UILabel的用户交互开关,默认是关闭的
        self.isUserInteractionEnabled = true
      // 添加一个长按的手势
        let longGes = UILongPressGestureRecognizer(target: self, action: #selector(contentLongPressed(gestureRecognizer:)))
        addGestureRecognizer(longGes)
    }
    
    @objc private func contentLongPressed(gestureRecognizer:UILongPressGestureRecognizer) {
        // 长按结束状态时,执行功能
        if gestureRecognizer.state == .ended {
            
            becomeFirstResponder()
            // 一个App只能有一个UIMenuController,所以通过单例来获得UIMenuController实例
            let menu = UIMenuController.shared
            // 创建一个名为“复制”的UIMenuItem,并设置对应的selector
            let copy = UIMenuItem(title: "复制", action: #selector(copyText(menuItem:)))
            menu.menuItems = [copy] // 这是一个数组,支持多个UIMenuItem

            // 显示UIMenuController
            menu.showMenu(from: self, rect: bounds)
        }
    }

    override var canBecomeFirstResponder: Bool {
      // 配置当前Label能成为第一响应者
        true
    }

    override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
        if action == #selector(copyText(menuItem:)) {
          // 配置是否允许Action执行,这个影响menu点击后的响应
            return true
        }
        return false
    }

    @objc private func copyText(menuItem: UIMenuItem) {
      // 实现复制到剪贴板功能
        UIPasteboard.general.string = self.text
    }
}

除了自己实现UIMenuItem对应的Action Selector,系统默认也有对应的功能,在UIResponderStandardEditActions协议里

@objc private func contentLongPressed(gestureRecognizer:UILongPressGestureRecognizer) {

    if gestureRecognizer.state == .ended {

      becomeFirstResponder()
      // 拿出菜单控制器单例
      let menu = UIMenuController.shared
      // 显示菜单控制器,默认是不可见状态
      menu.showMenu(from: self, rect: bounds)
    }
}

// 省略部分代码,请参考上面的代码
override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
    if action == #selector(copy(_:)) {
      // 匹配copy(_:)方法
      return true
    }
    return false
}
override func copy(_ sender: Any?) {
  // 重写UIResponderStandardEditActions协议里的copy方法
  	UIPasteboard.general.string = self.text
}

注意,直接对于UILabel实例进行UIMenuController配置,我发现未能实现功能,需要自己实现一个UILabel子类,在子类里实现UIMenuController的对应功能。当需要的时候,使用这个子类,就能实现UIMenuController的功能了。