2011-08-04 10 views
4

次のコードは、iOS 4.3(おそらく他のバージョンの場合もあります)では奇妙な動作を示しています。この例では、日付が4 Aug 2011 2:31 PMに設定されたUIDatePickerが表示されます。 UIDatePicker以下のUILabelは、参照の日付を表示します。下の3つのUIButtonsは1,5,8と表示され、minuteIntervalUIDatePickerに設定されています。UIDatePicker minuteIntervalを設定したときの奇妙な動作

タップ1 - UIDatePickerの選択された日付が4 Aug 2011 2:31 PMであり、分間隔が1であることが予期されることを示します。 5をタップ

は - UIDatePickerで選択した日付が4 Aug 2011 2:35 PMであることを示しており、分間隔が予想されている、5である(1時間を主張することができ切り捨てなければならないが、それは大きな問題ではありません)。

タップ10 - UIDatePickerの選択された日付が4 Aug 2011 2:10 PMであり、分間隔が10であることを示します。分間隔は正しいですが、選択した時間は2:10ですか? 1人は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]; 
} 

答えて

8

わかりましたので、私は明示的に設定することで動作を変更することができましたUIDatePicker日付への日付の値を分に丸めたint 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]; 
} 

ご注意:erval次のコードを使用して。それを考え出すのは楽しいことでした。

minuteIntervalへの呼び出しでアニメーションをオフにする方法を知っていますか? 5番と10番をクリックしたときの仮想スクロールはちょっと見苦しいものです。

+0

はありがとう...魔法のように働いた:) –

1

UIDatePickerで同じ問題が発生しました。時間を選択するたびに、選択された時間ではなく、UIで20分追加されます。私の場合は解決が簡単でしたが、ピッカーの値を設定する前にpicker.minuteInterval=5を設定してください。

これは他の人に役立つことを願っています。

6

Iは、ここ(アーク)..

- (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

をmmorisことにより、上記溶液を使用し、丸みを帯びた日付を返すメソッドを作成getRoundedDateの更新バージョンである:1:03となるよう上下に丸めること午後は、午後1時まで切り捨てと13:12には、Objective-Cのカテゴリーに、ここで午後1時

-(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

に切り上げさらに別の方法です!

私は、@ 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]; 
} 

... 

ボーナス方法:setMinimumDateRoundedByMinuteInterval:あなたは同じ動作を一致させるために、ピッカーの初期最小を設定することができます。 1つのリファクタは、コピーパスタではなく、実際の計算パートを独自のメソッドに抽象化することですが、私は自分自身でそれを最適化できると確信しています。 スウィフト

1

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 
} 
0

スウィフト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 
    }