设置minuteInterval时UIDatePicker奇怪的行为

时间:2011-08-04 20:46:12

标签: ios uidatepicker

以下代码在iOS 4.3下显示奇怪的行为(也许是其他版本)。在此示例中,显示日期设置为UIDatePicker的{​​{1}}。 4 Aug 2011 2:31 PM下方的UILabel显示参考日期。下面标有1,5,10的三个UIDatePicker设置了UIButtons上的minuteInterval

点击1 - 显示UIDatePicker中所选日期为UIDatePicker,并且分钟间隔为1,这是预期的。

点击5 - 显示4 Aug 2011 2:31 PM中的所选日期为UIDatePicker,并且分钟间隔为5,这是预期的(可以说时间应该向下舍入,但那是不是一个大问题。)

点击10 - 显示4 Aug 2011 2:35 PM中所选日期为UIDatePicker,分钟间隔为10.好分钟间隔是否正确,但所选时间是2:10?人们可能会预期2:40(如果向上舍入)或2:30(如果向下舍入)。

BugDatePickerVC.h

4 Aug 2011 2:10 PM

BugDatePickerVC.m

导入“BugDatePickerVC.h”

#import <UIKit/UIKit.h>

@interface BugDatePickerVC : UIViewController {
    NSDateFormatter *dateFormatter;
    NSDate *date;
    UIDatePicker *datePicker;
    UILabel *dateL;
    UIButton *oneB;
    UIButton *fiveB;
    UIButton *tenB;
}

- (void) buttonEventTouchDown:(id)sender;

@end

7 个答案:

答案 0 :(得分:8)

好的,我可以通过使用以下代码将UIDatePicker日期值明确设置为舍入到分钟间隔的日期来更改行为:

- (void) handleUIControlEventTouchDown:(id)sender
{
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    // Set the date picker's minute interval.
    NSInteger minuteInterval  = [sender tag];

    // Setting the date picker's minute interval can change what is selected on
    // the date picker's UI to a wrong date, it does not effect the date
    // picker's date value.
    //
    // For example the date picker's date value is 2:31 and then minute interval
    // is set to 10.  The date value is still 2:31, but 2:10 is selected on the
    // UI, not 2:40 (rounded up) or 2:30 (rounded down).
    //
    // The code that follow's setting the date picker's minute interval
    // addresses fixing the date value (and the selected date on the UI display)
    // .  In the example above both would be 2:30.
    datePicker.minuteInterval = minuteInterval;

    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    // Calculate the proper date value (and the date to be selected on the UI
    // display) by rounding down to the nearest minute interval.
    NSDateComponents *dateComponents = [[NSCalendar currentCalendar] components:NSMinuteCalendarUnit fromDate:date];
    NSInteger minutes = [dateComponents minute];
    NSInteger minutesRounded = ( (NSInteger)(minutes / minuteInterval) ) * minuteInterval;
    NSDate *roundedDate = [[NSDate alloc] initWithTimeInterval:60.0 * (minutesRounded - minutes) sinceDate:date];

    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    // Set the date picker's value (and the selected date on the UI display) to
    // the rounded date.
    if ([roundedDate isEqualToDate:datePicker.date])
    {
        // We need to set the date picker's value to something different than
        // the rounded date, because the second call to set the date picker's
        // date with the same value is ignored. Which could be bad since the
        // call above to set the date picker's minute interval can leave the
        // date picker with the wrong selected date (the whole reason why we are
        // doing this).
        NSDate *diffrentDate = [[NSDate alloc] initWithTimeInterval:60 sinceDate:roundedDate];
        datePicker.date = diffrentDate;
        [diffrentDate release];
    }
    datePicker.date = roundedDate;
    [roundedDate release];
}

注意UIDatePicker日期设置两次的部分。这很好玩。

任何人都知道如何关闭动画来调用minuteInterval?点击5然后点击10时的幻像滚动有点难看。

答案 1 :(得分:6)

我使用mmoris的上述解决方案并创建了一个返回舍入日期的方法..(对于ARC)

- (NSDate *)getRoundedDate:(NSDate *)inDate{

    NSDate *returnDate;
    NSInteger minuteInterval = 10;
    NSDateComponents *dateComponents = [[NSCalendar currentCalendar] components:NSMinuteCalendarUnit fromDate:inDate];
    NSInteger minutes = [dateComponents minute];
    NSInteger minutesRounded = ( (NSInteger)(minutes / minuteInterval) ) * minuteInterval;
    NSDate *roundedDate = [[NSDate alloc] initWithTimeInterval:60.0 * (minutesRounded - minutes) sinceDate:inDate];

    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    // Set the date picker's value (and the selected date on the UI display) to
    // the rounded date.
    if ([roundedDate isEqualToDate:inDate])
    {
       // We need to set the date picker's value to something different than
       // the rounded date, because the second call to set the date picker's
       // date with the same value is ignored. Which could be bad since the
       // call above to set the date picker's minute interval can leave the
       // date picker with the wrong selected date (the whole reason why we are
       // doing this).
       NSDate *diffrentDate = [[NSDate alloc] initWithTimeInterval:60 sinceDate:roundedDate];
       returnDate = diffrentDate;
       //[diffrentDate release];
    }

    returnDate = roundedDate;
    return returnDate;
}

答案 2 :(得分:4)

这是另一种方法,具有Objective-C类别!

我采取了@ zurbergram的舍入行为(上/下至最接近)和@mmorris的整体答案的精神,并提出了这个类别:

#import <UIKit/UIKit.h>

@interface UIDatePicker (SetDateRounded)

-(void)setMinimumDateRoundedByMinuteInterval:(NSDate *)minimumDate;
-(void)setDateRoundedByMinuteInterval:(NSDate *)date animated:(BOOL)animatedYesNo;

@end

@implementation UIDatePicker (SetDateRounded)

-(void)setDateRoundedByMinuteInterval:(NSDate *)date animated:(BOOL)animatedYesNo
{
    NSDateComponents *dateComponents = [[NSCalendar currentCalendar] components:NSMinuteCalendarUnit fromDate:date];
    NSInteger minutes = [dateComponents minute];
    NSInteger minutesRounded = roundf((float)minutes / (float)[self minuteInterval]) * self.minuteInterval;
    NSDate *roundedDate = [[NSDate alloc] initWithTimeInterval:60.0 * (minutesRounded - minutes) sinceDate:date];
    [self setDate:roundedDate animated:animatedYesNo];
}

-(void)setMinimumDateRoundedByMinuteInterval:(NSDate *)date
{
    NSDateComponents *dateComponents = [[NSCalendar currentCalendar] components:NSMinuteCalendarUnit fromDate:date];
    NSInteger minutes = [dateComponents minute];
    NSInteger minutesRounded = roundf((float)minutes / (float)[self minuteInterval]) * self.minuteInterval;
    NSDate *roundedDate = [[NSDate alloc] initWithTimeInterval:60.0 * (minutesRounded - minutes) sinceDate:date];
    [self setMinimumDate:roundedDate];
}

@end

然后在您的实现中,您可以执行以下操作:

#import "UIDatePicker+SetDateRounded.h"

...

- (void)viewDidLoad
{
    [super viewDidLoad];

    _datePicker.minuteInterval = 15;

    [_datePicker setMinimumDateRoundedByMinuteInterval:[NSDate date]];
    [_datePicker setDateRoundedByMinuteInterval:[NSDate date] animated:YES];
}

...

Bonus方法:setMinimumDateRoundedByMinuteInterval:允许您设置选择器的初始最小值以匹配相同的行为。一个重构是将实际计算部分抽象为自己的方法,而不是复制意大利面,但我相信人们可以为自己优化它。

答案 3 :(得分:3)

以下是getRoundedDate的更新版本:向上或向下舍入,以便下午1:03向下舍入到下午1:00和下午1:12到下午1:15

-(NSDate *)getRoundedDate:(NSDate *)inDate
{
    NSInteger minuteInterval = 15;
    NSDateComponents *dateComponents = [[NSCalendar currentCalendar] components:NSMinuteCalendarUnit fromDate:inDate];
    NSInteger minutes = [dateComponents minute];

    float minutesF = [[NSNumber numberWithInteger:minutes] floatValue];
    float minuteIntervalF = [[NSNumber numberWithInteger:minuteInterval] floatValue];

    // Determine whether to add 0 or the minuteInterval to time found by rounding down
    NSInteger roundingAmount = (fmodf(minutesF, minuteIntervalF)) > minuteIntervalF/2.0 ? minuteInterval : 0;
    NSInteger minutesRounded = ( (NSInteger)(minutes / minuteInterval) ) * minuteInterval;
    NSDate *roundedDate = [[NSDate alloc] initWithTimeInterval:60.0 * (minutesRounded + roundingAmount - minutes) sinceDate:inDate];

    return roundedDate;
}

答案 4 :(得分:1)

UIDatePicker的问题只有小时和分钟,每次我选择一个时间,选择器在UI中添加20分钟,而不是在选定的时间。在我的情况下,解决方案非常简单,在设置选择器的值之前设置picker.minuteInterval=5

希望这会对其他人有所帮助。

答案 5 :(得分:1)

Swift 中的

zurbergram 代码:

 register_post_type( 'series', array(

答案 6 :(得分:1)

Swift 4 版本

func round(date: Date, for minuteInterval: Int) -> Date {
        let dateComponents = Calendar.current.dateComponents([.minute], from: date)

        let minutes = dateComponents.minute!

        // Determine whether to add 0 or the minuteInterval to time found by rounding down

        let intervalRemainder = Double(minutes).truncatingRemainder(
            dividingBy: Double(minuteInterval)
        )

        let halfInterval = Double(minuteInterval) / 2.0

        let roundingAmount: Int
        if  intervalRemainder > halfInterval {
            roundingAmount = minuteInterval
        } else {
            roundingAmount = 0
        }

        let minutesRounded = minutes / minuteInterval * minuteInterval
        let timeInterval = TimeInterval(
            60 * (minutesRounded + roundingAmount - minutes)
        )

        let roundedDate = Date(timeInterval: timeInterval, since: date)

        return roundedDate
    }