【问题标题】: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 是唯一连接的事件,也会发生双击事件。

【问题讨论】:

    标签: iphone cocoa-touch uislider


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

              【讨论】:

                猜你喜欢
                • 2012-06-23
                • 1970-01-01
                • 1970-01-01
                • 2011-04-23
                • 2014-09-28
                • 1970-01-01
                • 1970-01-01
                • 2012-07-29
                相关资源
                最近更新 更多