UISlider 返回两个 Touch Up Inside 事件,为啥会这样?
Posted
技术标签:
【中文标题】UISlider 返回两个 Touch Up Inside 事件,为啥会这样?【英文标题】:UISlider returns two Touch Up Inside events, why does that happen?UISlider 返回两个 Touch Up Inside 事件,为什么会这样? 【发布时间】:2009-06-30 11:26:08 【问题描述】:我有一个滑块,用于在某处设置浮点值。我将 Value Changed 连接到我的 viewController 中的一个方法。这部分工作正常。
我需要知道用户何时开始触摸控件,但不必知道滑块更改的每一瞬间(我为此收到 Value Changed 事件)。所以我将 Touch Up Inside 事件连接到 viewController 中的另一个方法。
问题在于,当用户触摸 UISlider 控件时,该方法会被调用两次。怎么回事?它不适用于 UIButtons 或其他触摸事件,如 Touch Down。
我想我可以解决它,但这似乎是滑块控件处理触摸方式的错误。有人知道为什么会这样吗?
顺便说一句:即使 Touch Up Inside 是唯一连接的事件,也会发生双击事件。
【问题讨论】:
【参考方案1】:只是为了不因未来的更新而中断
[customSlider addTarget:self action:@selector(sliderDown:) forControlEvents:UIControlEventTouchDown];
[customSlider addTarget:self action:@selector(sliderAction:) forControlEvents:UIControlEventTouchUpInside];
- (void)sliderDown:(id)sender
sliderused = NO;
- (void)sliderAction:(id)sender
if(sliderused)
return;
sliderused = YES;
//Your Code Here
【讨论】:
【参考方案2】:如果你愿意对滑块进行子类化,你可以通过实现 endTrackingWithTouch 并且什么都不做来轻松解决这个问题:
- (void) endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event
这里唯一需要注意的是某些特定的 UIControlEvents 不会正确触发。我相信它们是以下几种,但我没有进行具体测试来查看哪些有效,哪些无效。但是触摸改变了,内部修饰肯定可以在没有重复触发的情况下工作。
UIControlEventTouchDragInside = 1 << 2,
UIControlEventTouchDragOutside = 1 << 3,
UIControlEventTouchDragEnter = 1 << 4,
UIControlEventTouchDragExit = 1 << 5,
【讨论】:
【参考方案3】:我也遇到了这个问题,我的解决方案是添加一个布尔值“allowEvent”。然后我将 UIControlEventTouchDown 连接到一个将“allowEvent”设置为 YES 的函数。
在 UIControlEventTouchUpInside 的选择器中,我检查了 allowEvent 是否为 YES,然后执行事件并将 allowEvent 设置为 NO。
那么事件即使触发两次也只会执行一次。
希望对你有帮助!
【讨论】:
【参考方案4】:我认为最简单的解决方案是使用上面提到的标志解决方案。
我创建了一个名为 (BOOL)pressed 的标志,并将其添加到 TouchUpInside 和 TouchDown 事件中。 所以,你只需要检查是否按下 == YES。
// On down event
pressed = YES;
// On up event
if (pressed)
pressed = NO;
// code here
希望对你有帮助。
哈密
【讨论】:
【参考方案5】:谢谢大家。我有同样的问题。这里有一些整数数学可以帮我解决这个问题:
static UInt32 counter = 0;
counter++;
if((counter/2)*2 != counter) return;
【讨论】:
哎哟!这是什么意思?只有当数字是偶数时才返回?最好改用if (counter % 2 == 0) return;
。
Apple 修复这个 bug 后会发生什么,这个解决方案不会弄乱你的应用程序吗?我强烈建议按照下面 bentech 的建议设置一个标志。【参考方案6】:
我刚刚尝试过,我注意到同样的行为。它从两个地方调用,首先从 UISlider 的 endTrackingWithTouch:withEvent: 方法(由 UIControl 的 touchesEnded:withEvent: 方法调用),然后从同一个 UIControl 的 touchesEnded:withEvent: 方法(首先调用 endTrakingWithTouch:withEvent: 方法) .
此外,当触摸在滑块之外结束时,endTrackingWithTouch:withEvent: 方法只会调用一次该方法。 touchesEnded:withEvent: 方法调用 this,但不会像在控件内触摸结束时那样调用回调。
无论如何,为什么要连接 Touch Up Inside?您想知道用户何时开始触摸控件吗?我认为您应该连接 Touch Down 而不是 Touch Up Inside。
编辑:我看到您需要更改的值,并且更改的值被频繁调用。我刚刚重新运行测试,并注意到以下内容。更改的值在两个内部调用之间调用。也许你可以用它做点什么?
【讨论】:
滑动完成后我需要做一些事情。 Touch Down 在滑动完成之前触发,Value Changed 在滑动发生时触发,这太频繁了。 我改变了我原来的答案:)【参考方案7】:由于我之前的评论没有受到好评,我决定想出一个简单的解决方法来解决这个问题,以防有人感兴趣。
我知道这不是世界上最有效的解决方案,但它的工作原理是一样的。
我创建了两个方法:sliderUp 和 sliderChanged 分别链接到 TouchUp 和 ValueChanged。我还创建了一个全局 int 变量(timesFired,如果你愿意的话)设置为初始设置为零
在 sliderUp 方法中,我放置了任何我不介意触发两次的代码。在我的情况下,如果滑块不在顶部,我会将滑块放回底部(如解锁功能的滑块)。我还在延迟后将 timesFired 重置为零。允许调用其他方法。以防万一。 (performSelector: withObject: afterDelay: 如果你不知道该怎么做)
在 sliderChanged 方法中,我首先有一个 if 语句:if(timesFired
只要用户抬起手指,timeFired 就会被设置回零,整个过程可以重新开始。
现在,只要我弄清楚如何在滑块到达顶部后将其冻结,我就会对这个解决方案感到满意。 (简单地禁用它会起作用吗?)
【讨论】:
【参考方案8】:此错误已在 4.2 中得到修复。 我现在使用 Dan 的代码如下:
static UInt32 counter = 0;
if ([[UIDevice currentDevice].systemVersion compare: @"4.2" options: NSNumericSearch] == NSOrderedAscending)
counter++;
if((counter/2)*2 != counter) return;
【讨论】:
啊!为什么除法和乘法只是为了区分奇数和偶数?使用模数!if (counter % 2 == 0) return;
【参考方案9】:
一个简单的解决方案,如果 Apple 将来修复此功能(?),它不会中断 就是添加一个属性,存储自上次交互以来的时间。 如果距离上次交互时间太短,则退出。
(在下面的代码中,latestTimeMark,最初在viewDidLoad中设置为当前时间)
NSDate *now = [NSDate date];
double nowDouble = [now timeIntervalSince1970];
double difference = nowDouble - self.latestTimeMark;
self.latestTimeMark = nowDouble;
//NSLog(@"difference is now: %f", difference);
if(difference<0.01f) return;
【讨论】:
以上是关于UISlider 返回两个 Touch Up Inside 事件,为啥会这样?的主要内容,如果未能解决你的问题,请参考以下文章
同时使用 touch down 和 touch up 手势识别器
第二个视图控制器中的 UIButton - Touch Up Inside 不起作用(Touch Down 可以)