长按后如何跟踪按钮选择?

Posted

技术标签:

【中文标题】长按后如何跟踪按钮选择?【英文标题】:How to track button selection after long press? 【发布时间】:2013-12-23 09:20:54 【问题描述】:

我试图模仿键盘的长按提示 UIButton 控件的字母。我要做的是长按 UIButton,在按住按钮后显示 3 个新按钮并选择这 3 个新按钮之一。就像键盘字母建议一样。

我该怎么做?任何的想法? 谢谢

【问题讨论】:

【参考方案1】:

你有UIControl 只是为了那个UILongPressGestureRecognizer 并且可以通过minimumPressDuration属性设置发稿时间

如果您希望UIButton 上的这种行为,您必须将此手势识别器添加到按钮并处理第一次调用(单击)。

【讨论】:

我已经将 UILongPressGestureRecogniser 添加到第一个按钮,但问题是当我将手指移动到第二个按钮时(第一个按钮仍然长按),我没有得到第二个按钮被触摸【参考方案2】:

您在 UIControl 上有一套完整的事件(UIButton 是它的子类)来处理您需要的所有触摸事件:

enum 
   UIControlEventTouchDown           = 1 <<  0,
   UIControlEventTouchDownRepeat     = 1 <<  1,
   UIControlEventTouchDragInside     = 1 <<  2,
   UIControlEventTouchDragOutside    = 1 <<  3,
   UIControlEventTouchDragEnter      = 1 <<  4,
   UIControlEventTouchDragExit       = 1 <<  5,
   UIControlEventTouchUpInside       = 1 <<  6,
   UIControlEventTouchUpOutside      = 1 <<  7,
   UIControlEventTouchCancel         = 1 <<  8,

   UIControlEventValueChanged        = 1 << 12,

   UIControlEventEditingDidBegin     = 1 << 16,
   UIControlEventEditingChanged      = 1 << 17,
   UIControlEventEditingDidEnd       = 1 << 18,
   UIControlEventEditingDidEndOnExit = 1 << 19,

   UIControlEventAllTouchEvents      = 0x00000FFF,
   UIControlEventAllEditingEvents    = 0x000F0000,
   UIControlEventApplicationReserved = 0x0F000000,
   UIControlEventSystemReserved      = 0xF0000000,
   UIControlEventAllEvents           = 0xFFFFFFFF
;
UIControlEventTouchDown 将在您触摸按钮时触发 如果您继续按住按钮,UIControlEventTouchDownRepeat 将触发(请注意,此事件将触发多次,因此您应该只处理第一个) - 在这里您应该显示弹出框 UIControlEventTouchDragExit 将在您将手指从按钮中拖出时触发 - 您应该在此处隐藏弹出框 UIControlEventTouchDragEnter 将在您将手指拖入按钮时触发 - 在这里您应该显示弹出框 当您从按钮上抬起手指时,UIControlEventTouchUpInsideUIControlEventTouchUpOutsideUIControlEventTouchCancel 将触发 - 您应该在此处隐藏弹出框 等

更新 不过,您将需要实现一些逻辑来处理在弹出框内拖动手指(因为您将从按钮中拖出)。

【讨论】:

【参考方案3】:

这已经很老了,但是因为我遇到了同样的问题,所以我会提出我的解决方案。

我的键盘由类 Keyboard 布局和创建,派生自 UIView 每个字母按钮都是从 UIButton 派生的 LetterButton 类。 键盘实现了一个协议,该协议处理来自按钮的 KeyPressed 事件。

对于主键盘的每个按钮,都会应用一个 UILongPressGestureRecognizer:

let longTouchRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(onButtonLongPressed))
longTouchRecognizer.cancelsTouchesInView = false
button.addGestureRecognizer(longTouchRecognizer)
button.delegate = self

@objc func onButtonLongPressed (_ sender: UIGestureRecognizer)

    if (sender.state == .began)
    
        guard let tag = sender.view?.tag else  return 
        createPopupView(button: buttons[tag])
    

必须将 cancelsTouchesInView 设置为 false,否则我们将不会收到任何进一步的事件!

在一个按钮上长按时,会创建一个弹出视图,在所触摸的按钮上方有一个或多个按钮。我们可以直接从触摸的按钮滑动到这些按钮。

LetterButton类的实现:

class LetterButton : UIButton

  var delegate : LetterButtonDelegate?
  var isInside = false

这是从键盘类调用的:

  func setIsInside(val: Bool)
  
    if (val)
    
        if (!isInside)
        
            setBackgroundColor(UIColor.lightGray, for: .normal)
        
    
    else
    
        if (!isInside)
        
            setBackgroundColor(UIColor.white, for: .normal)
       
    
    isInside = val

其实我这里只需要Keyboard类的按钮

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?)

    if let touch = touches.first
    
        let point = touch.location(in: self)
        delegate?.onBegan(button: self, point: point)
    

    super.touchesBegan(touches, with: event)

只要我们将触摸移到按钮之外,移动信息就会发送到Keyboard类:

override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?)

    if let touch = touches.first
    
        let point = touch.location(in: self)
        if !bounds.contains(point)
        
            delegate?.onMoved(point: convert(point, to: superview))
            return
        
    

    super.touchesMoved(touches, with: event)

这是实际处理按钮字母的地方

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?)

    if let touch = touches.first
    
        let point = touch.location(in: self)
        delegate?.onEnded(point: convert(point, to: superview))
    

    super.touchesEnded(touches, with: event)


正如我们所见,LetterButton 类建立了以下需要由 Keyboard 类实现的协议:

protocol LetterButtonDelegate

    func onBegan(button: LetterButton, point: CGPoint)
    func onMoved(point: CGPoint)
    func onEnded(point: CGPoint)

Keyboard 类中的协议实现如下:

最初被触摸的按钮存储在这里

func onBegan(button: LetterButton, point: CGPoint)

    buttonPressed = button

为我们滑动的按钮处理背景颜色变化

func onMoved(point: CGPoint)

    let _ = findPopupButton(point: point)

触摸结束的处理

func onEnded(point: CGPoint)

    // Check if touch ended on a popup button
    if let button = findPopupButton(point: point)
    
        // yes, let the keyboard process the key
        delegate?.KeyPressed(key: button.title(for: .normal)!)
        button.setIsInside(val: false)

        // remove popupbuttons
        popupView?.removeFromSuperview()
        popupView = nil
    
    else
    
        // remove popup buttons if touch ended anywhere else
        if popupView != nil
        
            popupView!.removeFromSuperview()
            popupView = nil

        

        // buttons is an array of all normal keyboard buttons
        // we use it to check if the button, where the touch ended is the same where the touch began
        for button in buttons
        
            if (button.frame.contains(point))
            
                if (button.button.tag == buttonPressed?.tag)
                
                    // Still on same button, process the key
                    delegate?.KeyPressed(key: button.button.title(for: .normal)!)              break
                
            
        


    



// Let's see if we are moving within the bounds of a popup button
func findPopupButton (point: CGPoint) -> LetterButton?

    var result : LetterButton? = nil

    if (popupView != nil)
    
        if (popupView!.frame.contains(point))
        
            for sub in popupView!.subviews
            
                if (sub.isKind(of: LetterButton.self))
                
                    let button = sub as! LetterButton
                    let frame = popupView!.convert(button.frame, to: self)

                    if (frame.contains(point))
                    
                        button.setIsInside(val: true)
                        result = button
                    
                    else
                    
                        button.setIsInside(val: false)
                    
                
            
        
    

    return result

【讨论】:

以上是关于长按后如何跟踪按钮选择?的主要内容,如果未能解决你的问题,请参考以下文章

长按后选择复制图像时,swift uitextview html图像会导致崩溃

长按后 EditText 不显示默认的 ContextMenu

长按后如何禁用 UICollectionViewCell 上的 UILongPressGestureRecognizer?

长按后抬起手指时iOS中没有Javascript事件?

如何在 Android 中使用长按事件

IOS Swift WkWebview如何屏蔽长按