【问题标题】:Objective-C: UIDatePicker UIControlEventValueChanged only fired on second selectionObjective-C:UIDatePicker UIControlEventValueChanged 仅在第二次选择时触发
【发布时间】:2013-10-15 14:50:03
【问题描述】:

第一次使用 UIDatePickers。首先,我只是尝试使用从 datePicker 中选择的任何值(设置为倒计时模式)来更新文本字段。

它有效,但仅在用户第二次选择时间时有效。我的操作,durationSelected() 只是第二次调用,所以更新 textField 没有问题。

这是我在情节提要中配置日期选择器的方式:

以下是对 Value Changed 触发的操作:

来自 DetailViewController.m

- (IBAction)durationSelected:(UIDatePicker *)sender
{
    self.durationTextField.text = [NSString stringWithFormat:@"%f seconds", sender.countDownDuration];
}

我试过设置一个默认值,没有效果。

发生了什么事?

【问题讨论】:

  • 你能定义“用户第二次选择时间”吗?这实际上是否需要用户将日期选择器更改为默认时间以外的时间,然后再次更改?或者您是否将点击/触摸视为时间选择?我只想指出,考虑到操作事件的值已更改,用户必须从默认值更改时间。
  • 第二次更改是显示第一次还是第二次?
  • 看起来需要重置一些计时器
  • 这里有一些澄清。当用户第一次更改时间时,什么也没有发生。当用户再次更改时间时,会触发 Value Changed 事件,并且第二次选择会填充文本字段。无论是否设置了默认值,都会发生这种情况。谢谢!
  • @hussainShabbir 你能详细说明一下吗?

标签: ios objective-c uidatepicker


【解决方案1】:

当 iOS 7.0.3 UIDatePicker 在 UIDatePickerModeCountDownTimer 模式下使用时,我看到了类似的错误。 第一次用户通过滚动滚轮更改值时,选择器不会触发与 UIControlEventValueChanged 事件关联的目标操作。它适用于后续更改。

以下是一种有效的解决方法。只需将设置 countDownDuration 初始值的代码封装到主循环的调度块中即可。每次轮子旋转到新值时,您的目标动作方法都会触发。这种方法几乎没有开销,并且在 iPhone 4 和 iPad 4 上运行良好。

dispatch_async(dispatch_get_main_queue(), ^{
    self.myDatePicker.countDownDuration = (NSTimeInterval) aNewDuration ;
});

【讨论】:

  • 太棒了!这个错误仍然存​​在于 iOS 8.1 中,您的解决方法已修复它。再次。
  • 谢谢! iOS 10.3 仍然存在错误,但这对我有用。
  • 效果很好! iOS 11 中仍然存在错误,但此解决方案对我有用
  • 在 iOS 11.2 模拟器中对我不起作用;我通过添加延迟来修复它:DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + .seconds(1)) { picker.countDownDuration = duration }希望这对某人有所帮助。
  • 非常感谢。在 iOS 11.2 + 下,延迟的技巧也适用于我
【解决方案2】:

这似乎是 UIDatePicker 的 iOS 7 实现中的一个错误。我建议在上面设置一个雷达。

在 iOS 6 SDK 上构建并在 iOS 6 设备上运行可以工作,而在 iOS 7 设备上运行则不行。

您可以通过将这行代码添加到您的 - (void)viewDidLoad 方法来修复它

[self.datePicker setDate:[NSDate date] animated:YES];

【讨论】:

  • @fivewood 这仍然适用于我在 9.3 中使用 swift,你能提供一个示例项目吗?
【解决方案3】:

我不确定,这是有根据的猜测:

这可能是因为 iOS 仅在日期选择器的值更改由轮子动画引起时才跟踪它们。所以它会在你的第一个“滚动”上设置值,但只检测到第二个发生了变化。

正如我所说,我无法确定原因,但解决方法应该很简单:只需在视图加载后使用 setDate: animated: 以编程方式设置起始日期:

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    [self.picker setDate:[NSDate dateWithTimeIntervalSinceNow:0] animated:true ];   
}

它似乎对我有用。

【讨论】:

    【解决方案4】:

    还有一个类似的错误,即在您将其旋转到全 0 后,它不会在第一次更改时触发,它会滑到第一分钟。

    鉴于这两个问题,我只是使用蛮力方法来解释所有这些废话(假设 Apple 根本没有兴趣解决这个问题)。

    在 viewDidLoad() 中:

     NSTimer scheduledTimerWithTimeInterval:0.750 repeats:YES block:^(NSTimer * _Nonnull timer) {
         [self timePickerDidChange:nil];
     }];
    

    您只需继续自己调用更改事件即可。只要它偏离当前值(即self.timePicker.countDownDuration 那么它就可以顺利运行。确保您的 didChange 代码不会像网络调用那样做任何大事:)

    【讨论】:

      【解决方案5】:

      您可以尝试设置 countDownTimer 值(如果您在倒计时模式下使用 datePicker)。但请确保在呈现选择器后在完成块内设置此属性。

      【讨论】:

        【解决方案6】:

        呈现选择器后的以下代码在 Xcode 9.4 beta、iOS 11.4 中为我工作。

                picker.countDownDuration = 0
                picker.countDownDuration = 3600 // 1 Hour
        

        【讨论】:

          【解决方案7】:

          我在使用 Swift 4.0 的 Xcode 10、iOS 12.0.1 中取得了以下成功:

          以其他答案为指导,我最终让UITextFields 代表回复:

          func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
            if let _ = textField.inputView as? UIDatePicker {
             //In my case I had more than one text field who's delegate would fire this method
             //So I checked to see if the input view was a date picker before continuing
             //If you have only one "delegated" text field then there's probably
             //no need for a check
             perform(#selector(setDatePicker), with: nil, afterDelay: 0)
            }
            return true
          }
          
          @objc func setDatePicker() {
            Thread.doBlockOnMainThread {
             self.theTimePicker.countDownDuration = 1000 //or whatever
            }
          }
          

          Thread.doBlockOnMainThread(_) 在哪里:

          extension Thread {
              class func doBlockOnMainThread(_ block: () -> Void) {
                  if !Thread.isMainThread {
                      DispatchQueue.main.sync(execute: {
                          block()
                      })
                  } else {
                      block()
                  }
              }
          }
          

          顺便说一句,我发现不仅UIDatePicker 首次出现时,而且用户错误地尝试将倒计时值设置为零时。 DatePicker 按预期自动移动到1,但接下来的值更改也不会触发所需的目标。

          【讨论】:

            【解决方案8】:

            以上方法均不适用于 iOS 13 / XCode 11.4.1。我的解决方案是对文本字段 UITextFieldDelegate 使用“textFieldDidBeginEditing”委托方法,因为日期选择器需要在视图中并设置动画以模拟“第一个”选择,所以在第二次选择(用户认为第一次选择)时,UIControlEventValueChanged 方法是触发。所以,是这样的:

            - (void)textFieldDidBeginEditing:(UITextField *)textField {
            
                [self.datePicker setDate: date]; //date is whatever date you want to set
            
            }
            

            在我的方法中,在第一次运行时,我使用 NSCalendar 和 NSDateComponents 将日期变量设置为 5 分钟间隔,因为这正是我所需要的,然后我设置了 date = self.datePicker.date。

            除了用户手动选择 0 分钟的情况外,这有效..

            【讨论】:

              猜你喜欢
              • 2021-03-14
              • 1970-01-01
              • 1970-01-01
              • 2021-04-29
              • 1970-01-01
              • 1970-01-01
              • 2011-01-05
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多