长按后如何跟踪按钮选择?
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
将在您将手指拖入按钮时触发 - 在这里您应该显示弹出框
当您从按钮上抬起手指时,UIControlEventTouchUpInside
、UIControlEventTouchUpOutside
和 UIControlEventTouchCancel
将触发 - 您应该在此处隐藏弹出框
等
更新 不过,您将需要实现一些逻辑来处理在弹出框内拖动手指(因为您将从按钮中拖出)。
【讨论】:
【参考方案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?