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

时间:2013-12-23 09:20:54

标签: ios iphone uibutton uigesturerecognizer

我试图模仿长按键盘,建议用 UIButton 控制一封信。我想要做的是长按 UIButton ,按住按钮3新按钮显示并选择这3个新按钮中的一个。就像键盘字母的建议一样。 enter image description here

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

3 个答案:

答案 0 :(得分:1)

UIControl只有minimumPressDuration UIButton 您可以按{{1}}属性

设置按下的时间

如果您想在{{1}}上执行此操作,则必须将此手势识别器添加到按钮并处理第一次呼叫(单击)。

答案 1 :(得分:1)

你有一套完整的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将会触发(注意这个事件会多次触发,所以你应该只处理第一个) - 这里你应该显示popover
  • 当你将手指从按钮上拖出时,
  • UIControlEventTouchDragExit将会触发 - 在这里你应该隐藏弹出窗口
  • 将手指拖入按钮时,
  • UIControlEventTouchDragEnter将会触发 - 此处应显示弹出窗口
  • 当你从按钮上抬起手指时,
  • UIControlEventTouchUpInsideUIControlEventTouchUpOutsideUIControlEventTouchCancel将会触发 - 在这里你应该隐藏弹出窗口

<强>更新
你将有一些逻辑来实现处理弹出窗口内的手指(因为那时你将从按钮中拖出)。

答案 2 :(得分:1)

这已经很老了,但是由于我有同样的问题,我将提出解决方案。

我安排了键盘类并由UIView派生的类Keyboard创建 每个字母按钮都是从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

这是从Keyboard类调用的:

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

实际上,我只需要这里的键盘类按钮即可

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
}