【问题标题】:Does UILabel have any value to make it selectable?UILabel 是否有任何价值使其可选择?
【发布时间】:2016-10-11 23:51:21
【问题描述】:

UILabel 是否可以设置任何值以使其可选?

我有一个我想要选择的标签,(长按并显示一个副本 btn)有点像在 Safari 中。

【问题讨论】:

    标签: ios swift uilabel


    【解决方案1】:

    独立解决方案 (Swift 5)

    您可以调整来自@BJHSolutions 和 NSHipster 的解决方案,以制作以下独立的SelectableLabel

    import UIKit
    
    /// Label that allows selection with long-press gesture, e.g. for copy-paste.
    class SelectableLabel: UILabel {
        
        override func awakeFromNib() {
            super.awakeFromNib()
    
            isUserInteractionEnabled = true
            addGestureRecognizer(
                UILongPressGestureRecognizer(
                    target: self,
                    action: #selector(handleLongPress(_:))
                )
            )
        }
    
        override var canBecomeFirstResponder: Bool {
            return true
        }
        
        override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
            return action == #selector(copy(_:))
        }
    
        // MARK: - UIResponderStandardEditActions
        
        override func copy(_ sender: Any?) {
            UIPasteboard.general.string = text
        }
        
        // MARK: - Long-press Handler
        
        @objc func handleLongPress(_ recognizer: UIGestureRecognizer) {
            if recognizer.state == .began,
                let recognizerView = recognizer.view,
                let recognizerSuperview = recognizerView.superview {
                recognizerView.becomeFirstResponder()
                UIMenuController.shared.setTargetRect(recognizerView.frame, in: recognizerSuperview)
                UIMenuController.shared.setMenuVisible(true, animated:true)
            }
        }
        
    }
    

    【讨论】:

    • 如果你想让动作在文本上方居中浮动:``` let textWidth = sizeThatFits(CGSize(width: frame.size.width, height: CGFloat(MAXFLOAT))).width 让我们调整= CGRect(x:0.0,y:recognizerView.frame.midY,宽度:textWidth,高度:recognizerView.frame.height)UIMenuController.shared.setTargetRect(调整,in:recognizerSuperview)```
    • 嗨!我必须在 menuController.setMenuVisible 之前移动 recognizerView.becomeFirstResponder() 才能让第一次长按工作
    【解决方案2】:

    是的,您需要通过应用于您的 UILabel 的长按手势来实现 UIMenuController。 NSHipster 上有一篇很好的文章,但文章的要点如下。

    创建一个UILabel的子类并实现以下方法:

    override func canBecomeFirstResponder() -> Bool {
        return true
    }
    
    override func canPerformAction(action: Selector, withSender sender: AnyObject?) -> Bool {
        return (action == "copy:")
    }
    
    // MARK: - UIResponderStandardEditActions
    
    override func copy(sender: AnyObject?) {
        UIPasteboard.generalPasteboard().string = text
    }
    

    然后在您的视图控制器中,您可以向标签添加长按手势:

    let gestureRecognizer = UILongPressGestureRecognizer(target: self, action: "handleLongPressGesture:")
    label.addGestureRecognizer(gestureRecognizer)
    

    并用这种方法处理长按:

    func handleLongPressGesture(recognizer: UIGestureRecognizer) {
         if let recognizerView = recognizer.view,
             recognizerSuperView = recognizerView.superview
         {
             let menuController = UIMenuController.sharedMenuController()
             menuController.setTargetRect(recognizerView.frame, inView: recognizerSuperView)
             menuController.setMenuVisible(true, animated:true)
             recognizerView.becomeFirstResponder()
         }}
    

    注意:此代码直接取自 NSHipster 文章,我只是将其包含在此处以符合 SO 要求。

    【讨论】:

    • 您还需要在标签上启用用户交互。否则,手势将永远不会被识别。在handleLongPressGesture 方法中检查手势的状态也很重要。 NSHipster 的那篇文章做得不好,做得很糟糕。
    • 嗨!我必须在 menuController.setMenuVisible 之前移动 recognizerView.becomeFirstResponder() 才能让第一次长按工作
    【解决方案3】:

    UILabel 继承自 UIView,因此您只需向标签添加一个长按手势识别器。请注意,您必须将 isUserInteractionEnabled 更改为 true,因为标签默认为 false。

        import UIKit
    
        class ViewController: UIViewController {
            let label = UILabel()
    
            override func viewDidLoad() {
                view.addSubview(label)
                label.text = "hello"
                label.translatesAutoresizingMaskIntoConstraints = false
                label.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
                label.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
                let longPressGestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(longPressLabel(longPressGestureRecognizer:)))
                label.addGestureRecognizer(longPressGestureRecognizer)
                label.isUserInteractionEnabled = true
            }
    
            @objc private func longPressLabel (longPressGestureRecognizer: UILongPressGestureRecognizer) {
                if longPressGestureRecognizer.state == .began {
                    print("long press began")
                } else if longPressGestureRecognizer.state == .ended {
                    print("long press ended")
                }
    
            }
    
        }
    

    【讨论】:

      【解决方案4】:

      我已经实现了一个UILabel 子类,它提供了所需的所有功能。请注意,如果您将其与界面生成器一起使用,则需要调整 init 方法。

      /// A label that can be copied.
      class CopyableLabel: UILabel
      {
          // MARK: - Initialisation
      
          /// Creates a new label.
          init()
          {
              super.init(frame: .zero)
      
              let gestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPressGesture(_:)))
              self.addGestureRecognizer(gestureRecognizer)
      
              self.isUserInteractionEnabled = true
          }
      
          required init?(coder aDecoder: NSCoder)
          {
              fatalError("init(coder:) has not been implemented")
          }
      
          // MARK: - Responder chain
      
          override var canBecomeFirstResponder: Bool
          {
              return true
          }
      
          // MARK: - Actions
      
          /// Method called when a long press is triggered.
          func handleLongPressGesture(_ gestuerRecognizer: UILongPressGestureRecognizer)
          {
              guard let superview = self.superview else { return }
      
              let menuController = UIMenuController.shared
              menuController.setTargetRect(self.frame, in: superview)
              menuController.setMenuVisible(true, animated:true)
              self.becomeFirstResponder()
          }
      
          override func copy(_ sender: Any?)
          {
              UIPasteboard.general.string = self.text
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-03-08
        • 1970-01-01
        • 2011-02-22
        • 1970-01-01
        • 1970-01-01
        • 2010-10-25
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多