Show iPhone cut copy paste menu on UILabel

前端 未结 12 1270
半阙折子戏
半阙折子戏 2020-11-30 21:05
  1. Can we enable the cut copy paste menu for a UILabel as it is for a UITextField?

  2. If not, and I need to convert my UIL

12条回答
  •  悲&欢浪女
    2020-11-30 21:08

    2019 ...

    Save anyone typing:

    public class SomeComplexCustomView: UIView {
    
        @IBOutlet var oneOfYourLabels: UILabel!
        ... your other labels, boxes, etc
    
        public func makeThatLabelCopyable() {
            oneOfYourLabels.isUserInteractionEnabled = true
            addGestureRecognizer(UITapGestureRecognizer(
              target: self, action: #selector(self.copyMenu(sender:))))
            addGestureRecognizer(UILongPressGestureRecognizer(
              target: self, action: #selector(self.copyMenu(sender:))))
    
            // or use oneOfYourLabels.addGesture... to touch just on that item 
        }
    
        public override var canBecomeFirstResponder: Bool { return true }
    
        @objc func copyMenu(sender: Any?) {
            becomeFirstResponder()
            UIMenuController.shared.setTargetRect(bounds, in: self)
            // or any exact point you want the pointy box pointing to
            UIMenuController.shared.setMenuVisible(true, animated: true)
        }
    
        override public func copy(_ sender: Any?) {
            UIPasteboard.general.string = oneOfYourLabels.text
            // or any exact text you wish
            UIMenuController.shared.setMenuVisible(false, animated: true)
        }
    
        override public func canPerformAction(
          _ action: Selector, withSender sender: Any?) -> Bool {
            return (action == #selector(copy(_:)))
        }
    }
    

    It's that easy!


    One subtlety:

    One detail for better engineering:

    Notice we turn on first responder:

     public override var canBecomeFirstResponder: Bool { return true }
    

    Often, on a given screen with such a label, you either will or won't have a copyable link like this.

    So you'll very likely have something like:

    var linkTurnedOnCurrently: Bool = false
    
    func doShowThatLink( blah ) {
        linkAvailableOnThisScreen = true
        ... the various code above ...
    }
    
    func doShowThatLink( blah ) {
        linkAvailableOnThisScreen = false
        ... perhaps de-color the link, etc ...
    }
    

    Thus, in fact instead of this:

     public override var canBecomeFirstResponder: Bool { return true }
    

    be sure to do this:

     public override var canBecomeFirstResponder: Bool {
        if linkTurnedOnCurrently { return true }
        return super.canBecomeFirstResponder
     }
    

    (Note that it is not something like "return linkTurnedOnCurrently".)

提交回复
热议问题