在 UILabel 上显示 iPhone 剪切复制粘贴菜单

发布于 2024-08-01 17:01:44 字数 208 浏览 18 评论 0原文

  1. 我们可以像为 UITextField 一样为 UILabel 启用剪切复制粘贴菜单吗?

  2. 如果没有,并且我需要将 UILabel 转换为 UITextField,如何启用剪切复制粘贴菜单并且不允许修改内容?

  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 UILabel to UITextField, how can I enable the cut copy paste menu and not allow the content to be modified?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(12

爱本泡沫多脆弱 2024-08-08 17:01:45

我在 UILabel 上使用了复制  粘贴菜单,我只需为 canBecomeFirstResponder 返回 YES,然后调用 >[标签成为FirstResponder] 当所述标签出现在屏幕上时。 至于从 canBecomeFirstResponder 返回 YES,您可以使用类别创建自定义子类或修补 UILabel

@implementation UILabel (Clipboard)

- (BOOL) canBecomeFirstResponder
{
    return YES;
}

@end

类别解决方案感觉有点 hackish,但是如果您知道自己在做什么,那么它可能比子类化更容易。 我还在 GitHub 上发布了一个 示例项目,展示了如何显示简单的粘贴板菜单在 UILabel 上。

I got the copy & paste menu working on a UILabel, I just had to return YES for canBecomeFirstResponder and later call [label becomeFirstResponder] when the said label was to come on screen. As for returning YES from canBecomeFirstResponder, you can create a custom subclass or patch UILabel using a category:

@implementation UILabel (Clipboard)

- (BOOL) canBecomeFirstResponder
{
    return YES;
}

@end

The category solution feels a bit hackish, but if you know what you’re doing it might be easier than subclassing. I have also put up a sample project on GitHub that shows how to display a simple pasteboard menu on an UILabel.

相思故 2024-08-08 17:01:45

由于 @zoul 的回答,github 上的示例项目是可行的方法。 在撰写本文时,该项目实际上并未在剪贴板(粘贴板)上放置任何内容。 方法如下:

将此方法的 @zoul 实现更改为:

- (void) copy:(id)sender {
    UIPasteboard *pboard = [UIPasteboard generalPasteboard];
    pboard.string = self.text;  
}

The sample project on github due to @zoul's answer is the way to go. At the time of this writing, that project does not actually put anything on the clipboard (pasteboard). here is how:

Change @zoul's implementation of this method to:

- (void) copy:(id)sender {
    UIPasteboard *pboard = [UIPasteboard generalPasteboard];
    pboard.string = self.text;  
}
孤檠 2024-08-08 17:01:45

Swift 4 ☻ Xcode 9.2
通过使用 UIMenuController 我们可以做到这一点。

我创建了 IBDesignable 自定义 UILabel 类,您可以直接在情节提要上分配该类

@IBDesignable
class TapAndCopyLabel: UILabel {

    override func awakeFromNib() {
        super.awakeFromNib()
        //1.Here i am Adding UILongPressGestureRecognizer by which copy popup will Appears
        let gestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPressGesture(_:)))
        self.addGestureRecognizer(gestureRecognizer)
        self.isUserInteractionEnabled = true
    }

    // MARK: - UIGestureRecognizer
    @objc func handleLongPressGesture(_ recognizer: UIGestureRecognizer) {
        guard recognizer.state == .recognized else { return }

        if let recognizerView = recognizer.view,
            let recognizerSuperView = recognizerView.superview, recognizerView.becomeFirstResponder()
        {
            let menuController = UIMenuController.shared
            menuController.setTargetRect(recognizerView.frame, in: recognizerSuperView)
            menuController.setMenuVisible(true, animated:true)
        }
    }
    //2.Returns a Boolean value indicating whether this object can become the first responder
    override var canBecomeFirstResponder: Bool {
        return true
    }
    //3.Here we are enabling copy action
    override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
        return (action == #selector(UIResponderStandardEditActions.copy(_:)))

    }
    // MARK: - UIResponderStandardEditActions
    override func copy(_ sender: Any?) {
        //4.copy current Text to the paste board
        UIPasteboard.general.string = text
    }
}

输出:

在此处输入图像描述

Swift 4 ☻ Xcode 9.2.
By using UIMenuController we can do it.

I have created IBDesignable Custom UILabel class which you can assign on storyboard directly

@IBDesignable
class TapAndCopyLabel: UILabel {

    override func awakeFromNib() {
        super.awakeFromNib()
        //1.Here i am Adding UILongPressGestureRecognizer by which copy popup will Appears
        let gestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPressGesture(_:)))
        self.addGestureRecognizer(gestureRecognizer)
        self.isUserInteractionEnabled = true
    }

    // MARK: - UIGestureRecognizer
    @objc func handleLongPressGesture(_ recognizer: UIGestureRecognizer) {
        guard recognizer.state == .recognized else { return }

        if let recognizerView = recognizer.view,
            let recognizerSuperView = recognizerView.superview, recognizerView.becomeFirstResponder()
        {
            let menuController = UIMenuController.shared
            menuController.setTargetRect(recognizerView.frame, in: recognizerSuperView)
            menuController.setMenuVisible(true, animated:true)
        }
    }
    //2.Returns a Boolean value indicating whether this object can become the first responder
    override var canBecomeFirstResponder: Bool {
        return true
    }
    //3.Here we are enabling copy action
    override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
        return (action == #selector(UIResponderStandardEditActions.copy(_:)))

    }
    // MARK: - UIResponderStandardEditActions
    override func copy(_ sender: Any?) {
        //4.copy current Text to the paste board
        UIPasteboard.general.string = text
    }
}

Output:

enter image description here

半夏半凉 2024-08-08 17:01:45

我制作了一个开源 UILabel 子类,长按时显示带有“复制”选项的 UIMenuController:

GitHub 上的 HTCopyableLabel

I've made an open source UILabel subclass that shows a UIMenuController with a "Copy" option upon long press:

HTCopyableLabel on GitHub

时间你老了 2024-08-08 17:01:45

Swift 5.0Xcode 10.2 中,

直接在 ViewController 中将复制选项添加到 UILabel 中。

//This is your UILabel
@IBOutlet weak var lbl: UILabel!

//In your viewDidLoad()
self.lbl.isUserInteractionEnabled = true
let longPress = UILongPressGestureRecognizer.init(target: self, action: #selector((longPressFunctin(_:))))
self.lbl.addGestureRecognizer(longPress)

//Write these all functions outside the viewDidLoad()
@objc func longPressFunctin(_ gestureRecognizer: UILongPressGestureRecognizer) {
    lbl.becomeFirstResponder()
    let menu = UIMenuController.shared
    if !menu.isMenuVisible {
        menu.setTargetRect(CGRect(x: self.lbl.center.x, y: self.lbl.center.y, width: 0.0, height: 0.0), in: view)
        menu.setMenuVisible(true, animated: true)
    }
}

override func copy(_ sender: Any?) {
    let board = UIPasteboard.general
    board.string = lbl.text
}

override var canBecomeFirstResponder: Bool {
    return true
}

override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
    return action == #selector(copy(_:))
}

如果您想进一步概括这一点以适用于视图控制器中的多个标签,包括深埋在视图层次结构中的标签,请执行以下操作:

向视图控制器添加一个变量

private var currentLabelToCopy : UILabel? = nil

对于要添加副本的每个标签函数,基本上按照上面答案所说的在 viewDidLoad 中执行的操作。 这是 tableView 单元格内标签的示例:

cell?.detailTextLabel?.isUserInteractionEnabled = true
let longPress = UILongPressGestureRecognizer.init(target: self, action: #selector((longPressFunctin(_:))))
cell?.detailTextLabel?.addGestureRecognizer(longPress)

现在修改上面显示的函数,如下所示

@objc func longPressFunctin(_ gestureRecognizer: UILongPressGestureRecognizer) {
    if let lbl = gestureRecognizer.view as? UILabel
    {
        lbl.becomeFirstResponder()
        let menu = UIMenuController.shared
        if !menu.isMenuVisible {
            let frame = lbl.frame
            if let superview = lbl.superview
            {
                menu.setTargetRect(CGRect(x: frame.maxX - (lbl.width / 2), y: frame.maxY - (lbl.height / 2) - 5, width: 0.0, height: 0.0), in: superview)
                menu.setMenuVisible(true, animated: true)
                self.currentLabelToCopy = lbl
            }
        }
    }
}

override func copy(_ sender: Any?) {
    let board = UIPasteboard.general
    if let lbl = self.currentLabelToCopy
    {
        board.string = lbl.text
    }
}

这些保持不变:

override var canBecomeFirstResponder: Bool {
    return true
}

override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
    return action == #selector(copy(_:))
}

如果您有任何问题,另请参阅: https://stackoverflow.com/a/23839272/826946

In Swift 5.0 and Xcode 10.2

Add copy option to your UILabel directly in your ViewController.

//This is your UILabel
@IBOutlet weak var lbl: UILabel!

//In your viewDidLoad()
self.lbl.isUserInteractionEnabled = true
let longPress = UILongPressGestureRecognizer.init(target: self, action: #selector((longPressFunctin(_:))))
self.lbl.addGestureRecognizer(longPress)

//Write these all functions outside the viewDidLoad()
@objc func longPressFunctin(_ gestureRecognizer: UILongPressGestureRecognizer) {
    lbl.becomeFirstResponder()
    let menu = UIMenuController.shared
    if !menu.isMenuVisible {
        menu.setTargetRect(CGRect(x: self.lbl.center.x, y: self.lbl.center.y, width: 0.0, height: 0.0), in: view)
        menu.setMenuVisible(true, animated: true)
    }
}

override func copy(_ sender: Any?) {
    let board = UIPasteboard.general
    board.string = lbl.text
}

override var canBecomeFirstResponder: Bool {
    return true
}

override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
    return action == #selector(copy(_:))
}

If you want to generalize this further to work for more than one label in your view controller, including labels that are buried deep in the view hierarchy, do this:

Add a variable to your view controller

private var currentLabelToCopy : UILabel? = nil

For each label that you want to add the copy function to, do basically what the above answer says to do in viewDidLoad. Here's an example for a label inside a tableView cell:

cell?.detailTextLabel?.isUserInteractionEnabled = true
let longPress = UILongPressGestureRecognizer.init(target: self, action: #selector((longPressFunctin(_:))))
cell?.detailTextLabel?.addGestureRecognizer(longPress)

Now modify the functions shown above as follows

@objc func longPressFunctin(_ gestureRecognizer: UILongPressGestureRecognizer) {
    if let lbl = gestureRecognizer.view as? UILabel
    {
        lbl.becomeFirstResponder()
        let menu = UIMenuController.shared
        if !menu.isMenuVisible {
            let frame = lbl.frame
            if let superview = lbl.superview
            {
                menu.setTargetRect(CGRect(x: frame.maxX - (lbl.width / 2), y: frame.maxY - (lbl.height / 2) - 5, width: 0.0, height: 0.0), in: superview)
                menu.setMenuVisible(true, animated: true)
                self.currentLabelToCopy = lbl
            }
        }
    }
}

override func copy(_ sender: Any?) {
    let board = UIPasteboard.general
    if let lbl = self.currentLabelToCopy
    {
        board.string = lbl.text
    }
}

These stay the same:

override var canBecomeFirstResponder: Bool {
    return true
}

override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
    return action == #selector(copy(_:))
}

Also see this if you have any problems: https://stackoverflow.com/a/23839272/826946

猫七 2024-08-08 17:01:45

Swift 5.3 和 SwiftUI

为了在 SwiftUI 中实现此功能,我们可以使用 pableiros 创建一个带有 的组合的方法UIViewRepresentable

我们需要对 CopyableLabel 类进行两项更新,因为 iOS 13 中已弃用以下方法。

.setTargetRect(_,in:)

.setMenutVisible (_,animated)

我们可以通过使用 .showMenu(from:rect:) 方法轻松解决此问题。

这是更新后的 CopyableLabel 类。

class CopyableLabel: UILabel {

    override init(frame: CGRect) {
        super.init(frame: frame)
        self.sharedInit()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.sharedInit()
    }

    func sharedInit() {
        self.isUserInteractionEnabled = true
        self.addGestureRecognizer(UILongPressGestureRecognizer(target: self, action: #selector(self.showMenu)))
    }

    @objc func showMenu(sender: AnyObject?) {
        self.becomeFirstResponder()

        let menu = UIMenuController.shared

        if !menu.isMenuVisible {
            menu.showMenu(from: self, rect: self.bounds) // <-  we update the deprecated methods here
        }
    }

    override func copy(_ sender: Any?) {
        let board = UIPasteboard.general

        board.string = text

        let menu = UIMenuController.shared

        menu.showMenu(from: self, rect: self.bounds) // <- we update the deprecated methods here
    }

    override var canBecomeFirstResponder: Bool {
        return true
    }

    override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
        return action == #selector(UIResponderStandardEditActions.copy)
    }
}

然后,为了让这个类与 SwiftUI 一起工作,我们所要做的就是创建一个简单的 UIViewRepresentable 。

struct CopyableLabelView: UIViewRepresentable {

    let text: String
    private let label = CopyableLabel(frame: .zero)

    init(text: String) {
        self.text = text
    }

    func makeUIView(context: Context) -> UILabel {
        // Set the text for the label
        label.text = text

        // Set the content hugging priority so the UILabel's view is
        // kept tight to the text.
        label.setContentHuggingPriority(.required, for: .horizontal)
        label.setContentHuggingPriority(.required, for: .vertical)
        return label
    }

    func updateUIView(_ uiView: UILabel, context: Context) {
        // Handle when the text that is passed changes
        uiView.text = text
    }
}
  

Swift 5.3 and SwiftUI

To make this work in SwiftUI we can use the method that pableiros created an combine that with a UIViewRepresentable.

There are two updates that we need to make to the CopyableLabel class as the following methods were deprecated in iOS 13.

.setTargetRect(_,in:)

.setMenutVisible(_,animated)

We can easily fix this by using the .showMenu(from:rect:) method instead.

Here is the updated CopyableLabel class.

class CopyableLabel: UILabel {

    override init(frame: CGRect) {
        super.init(frame: frame)
        self.sharedInit()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.sharedInit()
    }

    func sharedInit() {
        self.isUserInteractionEnabled = true
        self.addGestureRecognizer(UILongPressGestureRecognizer(target: self, action: #selector(self.showMenu)))
    }

    @objc func showMenu(sender: AnyObject?) {
        self.becomeFirstResponder()

        let menu = UIMenuController.shared

        if !menu.isMenuVisible {
            menu.showMenu(from: self, rect: self.bounds) // <-  we update the deprecated methods here
        }
    }

    override func copy(_ sender: Any?) {
        let board = UIPasteboard.general

        board.string = text

        let menu = UIMenuController.shared

        menu.showMenu(from: self, rect: self.bounds) // <- we update the deprecated methods here
    }

    override var canBecomeFirstResponder: Bool {
        return true
    }

    override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
        return action == #selector(UIResponderStandardEditActions.copy)
    }
}

Then to get this class to work with SwiftUI all we have to do is create a simple UIViewRepresentable.

struct CopyableLabelView: UIViewRepresentable {

    let text: String
    private let label = CopyableLabel(frame: .zero)

    init(text: String) {
        self.text = text
    }

    func makeUIView(context: Context) -> UILabel {
        // Set the text for the label
        label.text = text

        // Set the content hugging priority so the UILabel's view is
        // kept tight to the text.
        label.setContentHuggingPriority(.required, for: .horizontal)
        label.setContentHuggingPriority(.required, for: .vertical)
        return label
    }

    func updateUIView(_ uiView: UILabel, context: Context) {
        // Handle when the text that is passed changes
        uiView.text = text
    }
}
  
夏日落 2024-08-08 17:01:45

如果有人仍然感兴趣,我已经分叉了 zoul 的示例项目并添加了对 ARC(以及其他一些功能)的支持:

https://github.com/zhbrass/UILabel-Clipboard

CopyLabel.h/.m 应该是您要找的

I've forked zoul's sample project and added support for ARC (and a couple of other features) if anyone's still interested:

https://github.com/zhbrass/UILabel-Clipboard

CopyLabel.h/.m should be what you're looking for

自由如风 2024-08-08 17:01:45

2019 ...

节省任何人的打字时间:

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(_:)))
    }
}

就是这么简单!


一个微妙之处:

更好的工程的一个细节:

请注意,我们打开第一响应者:

 public override var canBecomeFirstResponder: Bool { return true }

通常,在带有此类标签的给定屏幕上,您要么会有或不会有这样的可复制链接。

因此,您很可能会看到类似的内容:

var linkTurnedOnCurrently: Bool = false

func doShowThatLink( blah ) {
    linkAvailableOnThisScreen = true
    ... the various code above ...
}

func doShowThatLink( blah ) {
    linkAvailableOnThisScreen = false
    ... perhaps de-color the link, etc ...
}

因此,事实上,而不是这样:

 public override var canBecomeFirstResponder: Bool { return true }

请务必执行此操作:

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

(请注意,它不是类似于“return linkTurnedOnCurrently”之类的内容.)

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".)

甲如呢乙后呢 2024-08-08 17:01:45

重写 UITextField 实例的 textFieldShouldBeginEditing 方法,并将其设置为返回 NO 以禁用编辑。

看一下 UITextFieldDelegate< /code>协议了解更多详细信息。

Override the UITextField instance's textFieldShouldBeginEditing method, and set it to return NO in order to disable editing.

Take a look at the UITextFieldDelegate protocol for more details.

神回复 2024-08-08 17:01:45

如果你有多行文本,你应该使用 UITextView

设置委托:

func textView(_ textView: UITextView,
              shouldChangeTextIn range: NSRange,
              replacementText text: String) -> Bool {
    return false
}

它应该会神奇地工作:)

If you have multiline text, you should use UITextView

Set the delegate:

func textView(_ textView: UITextView,
              shouldChangeTextIn range: NSRange,
              replacementText text: String) -> Bool {
    return false
}

And it should work magically :)

ι不睡觉的鱼゛ 2024-08-08 17:01:45

@benvolioT 的 github 项目 是非常好的复制示例。 对于粘贴,请自定义 canPerformAction:withSender:
有关更多信息,请参阅示例 CopyPasteTile

@benvolioT's github project is very good example for copying. And for paste, customize canPerformAction:withSender:.
For more see example CopyPasteTile.

漆黑的白昼 2024-08-08 17:01:44

对于 Swift,你必须实现这个类:

import UIKit

class CopyableLabel: UILabel {

    override init(frame: CGRect) {
        super.init(frame: frame)
        self.sharedInit()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.sharedInit()
    }

    func sharedInit() {
        self.isUserInteractionEnabled = true
        let gesture = UILongPressGestureRecognizer(target: self, action: #selector(self.showMenu))
        self.addGestureRecognizer(gesture)
    }

    @objc func showMenu(_ recognizer: UILongPressGestureRecognizer) {
        self.becomeFirstResponder()
    
        let menu = UIMenuController.shared
    
        let locationOfTouchInLabel = recognizer.location(in: self)

        if !menu.isMenuVisible {
            var rect = bounds
            rect.origin = locationOfTouchInLabel
            rect.size = CGSize(width: 1, height: 1)
        
            menu.showMenu(from: self, rect: rect)
        }
    }

    override func copy(_ sender: Any?) {
        let board = UIPasteboard.general
    
        board.string = text
    
        let menu = UIMenuController.shared
    
        menu.setMenuVisible(false, animated: true)
    }

    override var canBecomeFirstResponder: Bool {
        return true
    }

    override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
        return action == #selector(UIResponderStandardEditActions.copy)
    }
}

在你的故事板中,只需使用 CopyableLabel 类对 UILabel 进行子类化

For Swift you have to implement this class:

import UIKit

class CopyableLabel: UILabel {

    override init(frame: CGRect) {
        super.init(frame: frame)
        self.sharedInit()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.sharedInit()
    }

    func sharedInit() {
        self.isUserInteractionEnabled = true
        let gesture = UILongPressGestureRecognizer(target: self, action: #selector(self.showMenu))
        self.addGestureRecognizer(gesture)
    }

    @objc func showMenu(_ recognizer: UILongPressGestureRecognizer) {
        self.becomeFirstResponder()
    
        let menu = UIMenuController.shared
    
        let locationOfTouchInLabel = recognizer.location(in: self)

        if !menu.isMenuVisible {
            var rect = bounds
            rect.origin = locationOfTouchInLabel
            rect.size = CGSize(width: 1, height: 1)
        
            menu.showMenu(from: self, rect: rect)
        }
    }

    override func copy(_ sender: Any?) {
        let board = UIPasteboard.general
    
        board.string = text
    
        let menu = UIMenuController.shared
    
        menu.setMenuVisible(false, animated: true)
    }

    override var canBecomeFirstResponder: Bool {
        return true
    }

    override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
        return action == #selector(UIResponderStandardEditActions.copy)
    }
}

In your storyboard just subclass the UILabel with CopyableLabel class

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文