簡體   English   中英

設置minuteInterval時UIDatePicker奇怪的行為

[英]UIDatePicker odd behavior when setting minuteInterval

以下代碼顯示了iOS 4.3下的奇怪行為(也許是其他版本)。 在此示例中,將顯示日期設置為4 Aug 2011 2:31 PMUIDatePicker UIDatePicker下方的UILabel顯示引用日期。 下面標記為minuteInterval的三個UIButtonsUIDatePicker上設置了minuteInterval

點擊1 - 顯示UIDatePicker中的選定日期為4 Aug 2011 2:31 PM ,並且分鍾間隔為1,這是預期的。

點擊5 - 顯示UIDatePicker中的選定日期為4 Aug 2011 2:35 PM ,並且分鍾間隔為5,這是預期的(可以說時間應該向下舍入,但這不是一個大問題) 。

點擊10 - 顯示UIDatePicker中的選定日期為4 Aug 2011 2:10 PM ,分鍾間隔為10.好的分鍾間隔是正確的,但所選時間是2:10? 人們可能會預期2:40(如果向上舍入)或2:30(如果向下舍入)。

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

BugDatePickerVC.m

導入“BugDatePickerVC.h”

@implementation BugDatePickerVC

- (id) init
{
    if ( !(self = [super init]) )
    {
        return self;
    }

    dateFormatter = [[NSDateFormatter alloc] init];
    dateFormatter.dateFormat = @"d MMM yyyy h:mm a";

    date = [[dateFormatter dateFromString:@"4 Aug 2011 2:31 PM"] retain];

    // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
    // Date picker
    datePicker = [[UIDatePicker alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 320.0f, 216.0f)];
    datePicker.date = date;
    datePicker.minuteInterval = 1;
    [self.view addSubview:datePicker];

    // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
    // Label with the date.
    dateL = [[UILabel alloc] initWithFrame:CGRectMake(10.0f, 230.0f, 300.0f, 32.0f)];
    dateL.text = [dateFormatter stringFromDate:date];
    [self.view addSubview:dateL];

    // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
    // Button that set the date picker's minute interval to 1.
    oneB = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    oneB.frame = CGRectMake(10.0f, 270.0f, 100.0f, 32.0f);
    oneB.tag = 1;
    [oneB setTitle:@"1" forState:UIControlStateNormal];
    [oneB   addTarget:self
               action:@selector(buttonEventTouchDown:)
     forControlEvents:UIControlEventTouchDown];
    [self.view addSubview:oneB];

    // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
    // Button that set the date picker's minute interval to 5.
    fiveB = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    fiveB.frame = CGRectMake(10.0f, 310.0f, 100.0f, 32.0f);
    fiveB.tag = 5;
    [fiveB setTitle:@"5" forState:UIControlStateNormal];
    [fiveB  addTarget:self
               action:@selector(buttonEventTouchDown:)
     forControlEvents:UIControlEventTouchDown];
    [self.view addSubview:fiveB];

    // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
    // Button that set the date picker's minute interval to 10.
    tenB = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    tenB.frame = CGRectMake(10.0f, 350.0f, 100.0f, 32.0f);
    tenB.tag = 10;
    [tenB setTitle:@"10" forState:UIControlStateNormal];
    [tenB   addTarget:self
               action:@selector(buttonEventTouchDown:)
     forControlEvents:UIControlEventTouchDown];
    [self.view addSubview:tenB];

    return self;
}

- (void) dealloc
{
    [dateFormatter release];
    [date release];
    [datePicker release];
    [dateL release];
    [oneB release];
    [fiveB release];
    [tenB release];

    [super dealloc];
}

- (void) buttonEventTouchDown:(id)sender
{
    datePicker.minuteInterval = [sender tag];
}

好的,我可以通過使用以下代碼將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時的幻像滾動有點不雅觀。

我使用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;
}

這是另一種方法,具有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:允許您設置選擇器的初始最小值以匹配相同的行為。 一個重構是將實際計算部分抽象為自己的方法,而不是復制意大利面,但我相信人們可以為自己優化。

這是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;
}

Swift中的 zurbergram代碼:

func getRoundedDate(inDate: NSDate) -> NSDate {

    let minuteInterval = 15
    let dateComponents = NSCalendar.currentCalendar().components(NSCalendarUnit.MinuteCalendarUnit, fromDate: inDate)
    let minutes = dateComponents.minute

    let minutesF = NSNumber(integer: minutes).floatValue
    let minuteIntervalF = NSNumber(integer: minuteInterval).floatValue

    // Determine whether to add 0 or the minuteInterval to time found by rounding down
    let roundingAmount = (fmodf(minutesF, minuteIntervalF)) > minuteIntervalF/2.0 ? minuteInterval : 0
    let minutesRounded = (minutes / minuteInterval) * minuteInterval
    let timeInterval = NSNumber(integer: (60 * (minutesRounded + roundingAmount - minutes))).doubleValue
    let roundedDate = NSDate(timeInterval: timeInterval, sinceDate: inDate )

    return roundedDate
}

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
    }

我在UIDatePicker上遇到了同樣的問題,只有小時和分鍾,每次我選擇一個時間,選擇器在UI中添加20分鍾,而不是在選定的時間。 在我的情況下,解決方案非常簡單,在設置選擇器的值之前設置picker.minuteInterval=5

希望這對其他人有所幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM