UISlider返回两个Touch Up Inside事件,为什么会这样?

时间:2009-06-30 11:26:08

标签: iphone cocoa-touch uislider

我有一个滑块,我用它来设置一个浮动值。我将 Value Changed 连接到我的viewController中的方法。那部分工作正常。

我需要知道用户何时开始触摸控件,但不一定知道滑块更改的每一个瞬间(我收到 Value Changed 事件)。所以我将 Touch Up Inside 事件连接到viewController中的另一个方法。

问题是,当用户触摸 UISlider 控件时,该方法会被调用两次。 WTF?使用 UIButtons 或其他触摸事件(例如 Touch Down )无法正常工作。

我认为,我可以解决它,但它似乎是滑块控件处理触摸的方式中的一个错误。有人知道为什么会这样吗?

BTW :即使 Touch Up Inside 是唯一连接的事件,也会发生双击事件。

9 个答案:

答案 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;