![](/img/trans.png)
[英]UIDatePicker shows incorrect minuteInterval until refreshed
[英]UIDatePicker odd behavior when setting minuteInterval
以下代碼顯示了iOS 4.3下的奇怪行為(也許是其他版本)。 在此示例中,將顯示日期設置為4 Aug 2011 2:31 PM
的UIDatePicker
。 UIDatePicker
下方的UILabel
顯示引用日期。 下面標記為minuteInterval
的三個UIButtons
在UIDatePicker
上設置了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
@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.