Objective-C:UIDatePicker UIControlEventValueChanged 仅在第二次选择时触发

Posted

技术标签:

【中文标题】Objective-C:UIDatePicker UIControlEventValueChanged 仅在第二次选择时触发【英文标题】:Objective-C: UIDatePicker UIControlEventValueChanged only fired on second selection 【发布时间】: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 你能详细说明一下吗? 【参考方案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 分钟的情况外,这有效..

【讨论】:

以上是关于Objective-C:UIDatePicker UIControlEventValueChanged 仅在第二次选择时触发的主要内容,如果未能解决你的问题,请参考以下文章

UIDatePicker 15 分钟增量 Swift

UIDatePicker 默认返回 Null?

UIDatePicker

iOS14 UIDatePicker 有一个偏移量

UIDatePicker 泄漏

UIdatePicker&UIPickerView简单使用