美文网首页
Swift: 给 Label 添加 UIMenuControll

Swift: 给 Label 添加 UIMenuControll

作者: 婉卿容若 | 来源:发表于2017-05-18 16:47 被阅读136次

功能


给 Label 添加复制功能并以 UIMenuController 显示展示

为什么


需要使用, 尽管很简单...
OC 时弄过, 但是用 Swift 写了一次, UIMenuController 一直显示失败..
看了别人写的笔记...发现都有问题

版本


基于 Swift3+

步骤 - 这是一个继承了 UILabel 的 label 控件


  1. 给 Label 打开交互响应
self.isUserInteractionEnabled = true
  1. 给 Label 添加长按手势(具体什么手势自己根据需求)
 let longPressGesture = UILongPressGestureRecognizer.init(target: self, action: #selector(longPressAction(gesture:)))
 self.addGestureRecognizer(longPressGesture)

手势事件

  func longPressAction(gesture: UILongPressGestureRecognizer){
        
        if gesture.state == .began{
        
            self.becomeFirstResponder()
            
            //let copyItem = UIMenuItem(title: "复制", action: #selector(copy(_:)))
            let menuVC = UIMenuController.shared
           // menuVC.menuItems = [copyItem]
            if menuVC.isMenuVisible {
                return
            }
            menuVC.setTargetRect(bounds, in: self)
            menuVC.setMenuVisible(true, animated: true)
        }
       
    }

说明:

  • self.becomeFirstResponder() 必须调用...但是 label 是否可以获取焦点是由canBecomeFirstResponder属性决定的, 它的默认值是 NO. 所以我们需求重写它.
    OC 中我们重写这个属性的 set 方法即可:
- (BOOL)canBecomeFirstResponder{
    return YES;
}```
Swift 中这个属性是一个可读的计算属性.
看很多人的笔记是这个重写的:
``` override func canBecomeFirstResponder() -> Bool {
      return true
  }

这种写法会报错...可能当时他们用的 Swift 版本允许
现在应该这个写:

override var canBecomeFirstResponder: Bool {
      return true
 }

不要试图给它复制...这是个只读属性

  • 注意判断长按手势的状态 gesture.state == .began,否则执行两次相关当妈
  1. 还必须要重写这个方法
 override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
        if action == #selector(copy(_:)){
            return true
        }else{
            return false
        }
        
    }

根据 action 去判断对应行为 给予适应的响应

  1. 复制操作
override func copy(_ sender: Any?) {
        let pastBoard = UIPasteboard.general
        pastBoard.string = self.text
    }

效果图:

展示图.jpg

ps: 相信你也注意到了我在第二步中没有给 menuVC 添加 menuItem, 但是为何会有上面的"拷贝"Item? 这是因为我们重写了系统提供的copy(_ :) 函数,所以系统默认给了 menuVC 一个 拷贝 的 menuItem
当我们不使用系统的方法时, 就需要自己给 menuVC 提供一个 menuItem, 自己定义 menuItem 可以给 title
当你自己定义了 menuItem 但是有使用了系统的copy(_ :)...你会发现比你预计的多一个 menuItem

以下给出了添加 Item 的完整代码

import Foundation
import UIKit

class RNMultiFunctionLabel: UILabel {
    
    override var canBecomeFirstResponder: Bool {
        return true
    }
    
    override func awakeFromNib() {
        super.awakeFromNib()
        self.addLongPressGesture()
    }
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        self.addLongPressGesture()
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
    
    override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
        if action == #selector(copyText(_:)){
            return true
        }else{
            return false
        }
        
    }
   
    override func copy(_ sender: Any?) {
        let pastBoard = UIPasteboard.general
        pastBoard.string = self.text
    }
    
    func copyText(_ sender: Any?){
        let pastBoard = UIPasteboard.general
        pastBoard.string = self.text
    }
}

//MARK: - private methods

extension RNMultiFunctionLabel {
    
    func addLongPressGesture() {
        
        self.isUserInteractionEnabled = true
        
        let longPressGesture = UILongPressGestureRecognizer.init(target: self, action: #selector(longPressAction(gesture:)))
        self.addGestureRecognizer(longPressGesture)
    }
    
    func longPressAction(gesture: UILongPressGestureRecognizer){
        
        if gesture.state == .began{
        
            self.becomeFirstResponder()
            
            let copyItem = UIMenuItem(title: "复制", action: #selector(copyText(_:)))
            let menuVC = UIMenuController.shared
            menuVC.menuItems = [copyItem]
            if menuVC.isMenuVisible {
                return
            }
            menuVC.setTargetRect(bounds, in: self)
            menuVC.setMenuVisible(true, animated: true)
        }
       
    }
}

使用


直接继承就行

demo


github

后续


最近重写了这咯扩展 label, 让点击以及长按手势可以根据你自己的要求实现事件
for example:

 contentLabel.pressClosure = { [weak self](gesture) in
            
            if let text = self?.contentLabel.text, text != "" {
                
                if gesture.state == .began{
                    
                    self?.contentLabel.pressAction(whichLabel: (self?.contentLabel)!)
                }
                
            }
        } 

这是对于长按手势事件的实现, 你可以在闭包内实现你的事件. 我这里self?.contentLabel.pressAction(whichLabel: (self?.contentLabel)!)是把要实现的操作放在了** RNMultiFunctionLabel**里,一些常用的操作整合在里面,就不用每次都去写

再后续

 var isOpenTapGesture: Bool = false { // 是否打开点击手势 -- default: false
        didSet{
            
            if isOpenTapGesture {
                
                self.addTapGesture()
            }
        }
    }
    var isOpenLongGesture: Bool = true { // 是否打开长按手势 -- default: true
        didSet {
             self.addLongPressGesture()
        }
    }

发现之前版本初始化之后打开手势无作用, 所以加上了属性监听.

相关文章

网友评论

      本文标题:Swift: 给 Label 添加 UIMenuControll

      本文链接:https://www.haomeiwen.com/subject/oebsxxtx.html