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

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

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

【问题讨论】:

    标签: ios iphone uibutton uigesturerecognizer


    【解决方案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
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-05-21
        • 1970-01-01
        • 1970-01-01
        • 2016-08-12
        相关资源
        最近更新 更多