我有一个滑块,我用它来设置一个浮动值。我将 Value Changed 连接到我的viewController中的方法。那部分工作正常。
我需要知道用户何时开始触摸控件,但不一定知道滑块更改的每一个瞬间(我收到 Value Changed 事件)。所以我将 Touch Up Inside 事件连接到viewController中的另一个方法。
问题是,当用户触摸 UISlider 控件时,该方法会被调用两次。 WTF?使用 UIButtons 或其他触摸事件(例如 Touch Down )无法正常工作。
我认为,我可以解决它,但它似乎是滑块控件处理触摸的方式中的一个错误。有人知道为什么会这样吗?
BTW :即使 Touch Up Inside 是唯一连接的事件,也会发生双击事件。
答案 0 :(得分:6)
这样就不会破坏未来的更新
[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
}
答案 1 :(得分:2)
如果你愿意对滑块进行子类化,你可以通过实现endTrackingWithTouch并且什么都不做来轻松解决这个问题:
- (void) endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event
{}
这里唯一需要注意的是,某些特定的UIControlEvents无法正常启动。我相信他们是以下的,但我没有做具体的测试,看看哪些有效,哪些无效。然而触摸变化和触摸内部肯定没有重复射击工作。
UIControlEventTouchDragInside = 1 << 2,
UIControlEventTouchDragOutside = 1 << 3,
UIControlEventTouchDragEnter = 1 << 4,
UIControlEventTouchDragExit = 1 << 5,
答案 2 :(得分:1)
我也有这个问题,我的解决方案是添加一个布尔“allowEvent”。然后我将UIControlEventTouchDown连接到一个将“allowEvent”设置为YES的函数。
在UIControlEventTouchUpInside的选择器中,我检查allowEvent是否为YES,然后执行该事件并将allowEvent设置为NO。
然后即使它发射两次,事件也只会被执行一次。
希望它有所帮助!
答案 3 :(得分:1)
我认为最简单的解决方案是使用上面提到的标志解决方案。
我已经创建了一个名为(BOOL)的标志,并将其添加到TouchUpInside和TouchDown事件中。 所以,你只需要检查是否按下==是。
// On down event
pressed = YES;
// On up event
if (pressed)
{
pressed = NO;
// code here
}
我希望它有所帮助。
哈密
答案 4 :(得分:1)
谢谢大家。我有同样的问题。这是一些解决它的整数数学:
static UInt32 counter = 0;
counter++;
if((counter/2)*2 != counter) return;
答案 5 :(得分:0)
我刚试过,我注意到了同样的行为。从两个地方调用它,首先来自UISlider的endTrackingWithTouch:withEvent:方法(由UIControl的touchesEnded:withEvent:方法调用),然后从相同的UIControl的touchesEnded:withEvent:方法(首先调用endTrakingWithTouch:withEvent:方法)
此外,当触摸在滑块外部结束时,该方法仅通过endTrackingWithTouch:withEvent:方法调用一次。 touchesEnded:withEvent:方法调用此方法,但不会调用回调,因为触摸在控件内部结束时也是如此。
无论如何,为什么要连接Touch Up Inside?您想知道用户何时开始触摸控件权限?我认为你应该连接Touch Down而不是Touch Up Inside。
编辑:我发现你需要更改的值,并且经常调用更改的值。我只是重新进行测试,并注意到以下内容。更改的值在两次内部调用之间调用。也许你可以用它做点什么?
答案 6 :(得分:0)
由于我之前的评论没有得到好评,所以我决定在有人感兴趣的情况下提出一个简单的解决方案。
我知道它不是世界上最有效的解决方案,但它的工作原理是一样的。
我创建了两个方法:sliderUp和sliderChanged分别链接到TouchUp和ValueChanged。我还创建了一个全局int变量(timesFired,如果你愿意)设置为初始设置为零
在sliderUp方法中,我放了任何我不介意触发两次的代码。在我的情况下,如果它不在顶部,我会将滑块向下射到底部(就像滑动解锁功能一样)。我也在延迟后将timesFired重置为零。允许调用其他方法。以防万一。 (performSelector:withObject:afterDelay:如果你不知道该怎么做)
在sliderChanged方法中,我首先使用if语句:if(timesFired&lt; 1){} (我还有一个if语句来确保我的滑块达到最大值)然后包含我想要只发生一次的所有代码,当滑块达到最大值时。为了确保该代码只被触发一次,我也增加了timesFired。
一旦用户抬起手指,就会将时间点恢复为零,整个过程可以重新开始。
现在,只要我知道如何在滑块到达顶部后冻结滑块,我就会对这个解决方案感到满意。 (会简单地禁用它吗?)
答案 7 :(得分:0)
此错误已于4.2开始修复。 我现在使用Dan的代码如下:
static UInt32 counter = 0;
if ([[UIDevice currentDevice].systemVersion compare: @"4.2" options: NSNumericSearch] == NSOrderedAscending) {
counter++;
if((counter/2)*2 != counter) return;
}
答案 8 :(得分:-1)
一个简单的解决方案,如果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;