我们是否可以为UILabel
启用UITextField
的剪切复制粘贴菜单?
如果没有,我需要将UILabel
转换为UITextField
,如何启用剪切复制粘贴菜单并且不允许修改内容?
答案 0 :(得分:39)
我得到了副本&粘贴菜单工作在UILabel
,我只需返回YES
canBecomeFirstResponder
,然后在屏幕上显示所述标签时调用[label becomeFirstResponder]
。对于从YES
返回canBecomeFirstResponder
,您可以使用类别创建自定义子类或补丁UILabel
:
@implementation UILabel (Clipboard)
- (BOOL) canBecomeFirstResponder
{
return YES;
}
@end
类别解决方案感觉有点hackish,但如果你知道你在做什么,它可能比继承更容易。我还提出了sample project on GitHub,其中显示了如何在UILabel
上显示简单的粘贴板菜单。
答案 1 :(得分:27)
对于Swift 3和Swift 4,你必须实现这个类:
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
self.addGestureRecognizer(UILongPressGestureRecognizer(target: self, action: #selector(self.showMenu)))
}
@objc func showMenu(sender: AnyObject?) {
self.becomeFirstResponder()
let menu = UIMenuController.shared
if !menu.isMenuVisible {
menu.setTargetRect(bounds, in: self)
menu.setMenuVisible(true, animated: true)
}
}
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)
}
}
在您的故事板中,只需将UILabel
与CopyableLabel
类
答案 2 :(得分:25)
将@ zoul的此方法实现更改为:
- (void) copy:(id)sender {
UIPasteboard *pboard = [UIPasteboard generalPasteboard];
pboard.string = self.text;
}
答案 3 :(得分:9)
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
}
}
<强>输出:强>
答案 4 :(得分:6)
我已经创建了一个开源UILabel子类,它显示了长按时带有“复制”选项的UIMenuController:
GitHub上的答案 5 :(得分:5)
如果有人仍然感兴趣,我已经分享了zoul的示例项目,并增加了对ARC(以及其他一些功能)的支持:
https://github.com/zhbrass/UILabel-Clipboard
CopyLabel.h / .m应该是你要找的东西
答案 6 :(得分:2)
覆盖UITextField
实例的textFieldShouldBeginEditing
方法,并将其设置为返回NO
以禁用编辑。
查看UITextFieldDelegate
协议了解更多详情。
答案 7 :(得分:1)
如果您有多行文字,则应使用input
设置代理:
UITextView
它应该神奇地工作:)
答案 8 :(得分:1)
保存输入的任何人
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(_:)))
}
}
就这么简单!
答案 9 :(得分:1)
要在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
}
}
答案 10 :(得分:0)
@benvolioT's github project是复制的好例子。对于粘贴,请自定义canPerformAction:withSender:
。
有关详细信息,请参阅示例CopyPasteTile。
答案 11 :(得分:0)
在 Swift 5.0 和 Xcode 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(_:))
}