Skip to content

Instantly share code, notes, and snippets.

@steve228uk
Last active February 26, 2022 21:08
Show Gist options
  • Star 16 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save steve228uk/f2362684bca527ff4f54 to your computer and use it in GitHub Desktop.
Save steve228uk/f2362684bca527ff4f54 to your computer and use it in GitHub Desktop.
Copyable UILabel
//
// SRCopyableLabel.swift
//
// Created by Stephen Radford on 08/09/2015.
// Copyright (c) 2015 Cocoon Development Ltd. All rights reserved.
//
import UIKit
class SRCopyableLabel: UILabel {
override public var canBecomeFirstResponder: Bool {
get {
return true
}
}
override init(frame: CGRect) {
super.init(frame: frame)
sharedInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
sharedInit()
}
func sharedInit() {
isUserInteractionEnabled = true
addGestureRecognizer(UILongPressGestureRecognizer(
target: self,
action: #selector(showMenu(sender:))
))
}
override func copy(_ sender: Any?) {
UIPasteboard.general.string = text
UIMenuController.shared.setMenuVisible(false, animated: true)
}
func showMenu(sender: Any?) {
becomeFirstResponder()
let menu = UIMenuController.shared
if !menu.isMenuVisible {
menu.setTargetRect(bounds, in: self)
menu.setMenuVisible(true, animated: true)
}
}
override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
return (action == #selector(copy(_:))
}
}
@steve228uk
Copy link
Author

Updated for Swift 2.3

@s2339956
Copy link

swift 3
error : Method does not override any method from its superclass

?!

@ehamberg
Copy link

ehamberg commented Oct 22, 2016

Swift 3 version:

import UIKit

class CopyableLabel: UILabel {

    override public var canBecomeFirstResponder: Bool {
        get {
            return true
        }
    }

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

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

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

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

    func showMenu(sender: Any?) {
        becomeFirstResponder()
        let menu = UIMenuController.shared
        if !menu.isMenuVisible {
            menu.setTargetRect(bounds, in: self)
            menu.setMenuVisible(true, animated: true)
        }
    }

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

        return false
    }
}

@s2339956
Copy link

Thanks for the reply, this is a great one

@petercampanelli
Copy link

petercampanelli commented Mar 1, 2017

Just found @ehamberg's comment with the Swift 3 version and it would be great if you updated the original so it reflects on your blog post!

@igoMobile
Copy link

Do you know of some limitations, when using CopyableLabel in the Today widget? I can see, that the functions canBecomeFirstResponder and canPerformAction are called, but menu is not shown... Thanks!

@nathandud
Copy link

Updated for iOS 13+

class CopyableLabel: UILabel {

    override public var canBecomeFirstResponder: Bool {
        get { 
            return true 
        }
    }

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

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

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

    override func copy(_ sender: Any?) {
        UIPasteboard.general.string = text
        UIMenuController.shared.hideMenu(from: self)
    }

    @objc func showMenu(sender: Any?) {
        becomeFirstResponder()
        let menu = UIMenuController.shared
        if !menu.isMenuVisible {
            UIMenuController.shared.showMenu(from: self, rect: bounds)
        }
    }

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

        return false
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment