UIDatePickerselect月份和年份
我只需要一个UIDatePicker
来select月份和年份。 我检查了课程参考文件。 看起来像UIDatePicker
是一个UIView
。 我想像UIPickerView
可能是一个子视图,我可以隐藏组件,如果我可以抓住它。 但不是。 这是不可能的。 那么我是否必须创build自己的自定义选取器? 有任何想法吗?
是的,你可能只想做自己的select器。 尽pipe如此,您不必将其子类化; 只需使用通用的UIPickerView
并从UIPickerViewDelegate
/ UIPickerViewDataSource
方法返回适当的值即可。
这是获得相同效果的解决scheme。 为了使用这段代码,你应该将UIPickerView
replace为“ CDatePickerViewEx
”的“Custom class”中的nib文件中的CDatePickerViewEx
。
.h文件
#import <UIKit/UIKit.h> @interface CDatePickerViewEx : UIPickerView <UIPickerViewDelegate, UIPickerViewDataSource> @property (nonatomic, strong, readonly) NSDate *date; -(void)selectToday; @end
.m文件
#import "CDatePickerViewEx.h" // Identifiers of components #define MONTH ( 0 ) #define YEAR ( 1 ) // Identifies for component views #define LABEL_TAG 43 @interface CDatePickerViewEx() @property (nonatomic, strong) NSIndexPath *todayIndexPath; @property (nonatomic, strong) NSArray *months; @property (nonatomic, strong) NSArray *years; -(NSArray *)nameOfYears; -(NSArray *)nameOfMonths; -(CGFloat)componentWidth; -(UILabel *)labelForComponent:(NSInteger)component selected:(BOOL)selected; -(NSString *)titleForRow:(NSInteger)row forComponent:(NSInteger)component; -(NSIndexPath *)todayPath; -(NSInteger)bigRowMonthCount; -(NSInteger)bigRowYearCount; -(NSString *)currentMonthName; -(NSString *)currentYearName; @end @implementation CDatePickerViewEx const NSInteger bigRowCount = 1000; const NSInteger minYear = 2008; const NSInteger maxYear = 2030; const CGFloat rowHeight = 44.f; const NSInteger numberOfComponents = 2; @synthesize todayIndexPath; @synthesize months; @synthesize years = _years; -(void)awakeFromNib { [super awakeFromNib]; self.months = [self nameOfMonths]; self.years = [self nameOfYears]; self.todayIndexPath = [self todayPath]; self.delegate = self; self.dataSource = self; [self selectToday]; } -(NSDate *)date { NSInteger monthCount = [self.months count]; NSString *month = [self.months objectAtIndex:([self selectedRowInComponent:MONTH] % monthCount)]; NSInteger yearCount = [self.years count]; NSString *year = [self.years objectAtIndex:([self selectedRowInComponent:YEAR] % yearCount)]; NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; [formatter setDateFormat:@"MMMM:yyyy"]; NSDate *date = [formatter dateFromString:[NSString stringWithFormat:@"%@:%@", month, year]]; return date; } #pragma mark - UIPickerViewDelegate -(CGFloat)pickerView:(UIPickerView *)pickerView widthForComponent:(NSInteger)component { return [self componentWidth]; } -(UIView *)pickerView: (UIPickerView *)pickerView viewForRow: (NSInteger)row forComponent: (NSInteger)component reusingView: (UIView *)view { BOOL selected = NO; if(component == MONTH) { NSInteger monthCount = [self.months count]; NSString *monthName = [self.months objectAtIndex:(row % monthCount)]; NSString *currentMonthName = [self currentMonthName]; if([monthName isEqualToString:currentMonthName] == YES) { selected = YES; } } else { NSInteger yearCount = [self.years count]; NSString *yearName = [self.years objectAtIndex:(row % yearCount)]; NSString *currenrYearName = [self currentYearName]; if([yearName isEqualToString:currenrYearName] == YES) { selected = YES; } } UILabel *returnView = nil; if(view.tag == LABEL_TAG) { returnView = (UILabel *)view; } else { returnView = [self labelForComponent: component selected: selected]; } returnView.textColor = selected ? [UIColor blueColor] : [UIColor blackColor]; returnView.text = [self titleForRow:row forComponent:component]; return returnView; } -(CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component { return rowHeight; } #pragma mark - UIPickerViewDataSource - (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView { return numberOfComponents; } -(NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component { if(component == MONTH) { return [self bigRowMonthCount]; } return [self bigRowYearCount]; } #pragma mark - Util -(NSInteger)bigRowMonthCount { return [self.months count] * bigRowCount; } -(NSInteger)bigRowYearCount { return [self.years count] * bigRowCount; } -(CGFloat)componentWidth { return self.bounds.size.width / numberOfComponents; } -(NSString *)titleForRow:(NSInteger)row forComponent:(NSInteger)component { if(component == MONTH) { NSInteger monthCount = [self.months count]; return [self.months objectAtIndex:(row % monthCount)]; } NSInteger yearCount = [self.years count]; return [self.years objectAtIndex:(row % yearCount)]; } -(UILabel *)labelForComponent:(NSInteger)component selected:(BOOL)selected { CGRect frame = CGRectMake(0.f, 0.f, [self componentWidth],rowHeight); UILabel *label = [[UILabel alloc] initWithFrame:frame]; label.textAlignment = UITextAlignmentCenter; label.backgroundColor = [UIColor clearColor]; label.textColor = selected ? [UIColor blueColor] : [UIColor blackColor]; label.font = [UIFont boldSystemFontOfSize:18.f]; label.userInteractionEnabled = NO; label.tag = LABEL_TAG; return label; } -(NSArray *)nameOfMonths { NSDateFormatter *dateFormatter = [NSDateFormatter new]; return [dateFormatter standaloneMonthSymbols]; } -(NSArray *)nameOfYears { NSMutableArray *years = [NSMutableArray array]; for(NSInteger year = minYear; year <= maxYear; year++) { NSString *yearStr = [NSString stringWithFormat:@"%i", year]; [years addObject:yearStr]; } return years; } -(void)selectToday { [self selectRow: self.todayIndexPath.row inComponent: MONTH animated: NO]; [self selectRow: self.todayIndexPath.section inComponent: YEAR animated: NO]; } -(NSIndexPath *)todayPath // row - month ; section - year { CGFloat row = 0.f; CGFloat section = 0.f; NSString *month = [self currentMonthName]; NSString *year = [self currentYearName]; //set table on the middle for(NSString *cellMonth in self.months) { if([cellMonth isEqualToString:month]) { row = [self.months indexOfObject:cellMonth]; row = row + [self bigRowMonthCount] / 2; break; } } for(NSString *cellYear in self.years) { if([cellYear isEqualToString:year]) { section = [self.years indexOfObject:cellYear]; section = section + [self bigRowYearCount] / 2; break; } } return [NSIndexPath indexPathForRow:row inSection:section]; } -(NSString *)currentMonthName { NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; [formatter setDateFormat:@"MMMM"]; return [formatter stringFromDate:[NSDate date]]; } -(NSString *)currentYearName { NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; [formatter setDateFormat:@"yyyy"]; return [formatter stringFromDate:[NSDate date]]; } @end
不 ,这不能使用股票UIDatePicker
。
UIDatePickerModeDate
dateselect器显示月份,月份的date和年份。 这些项目的确切顺序取决于区域设置。 这种模式的一个例子是[11月| 15 | 2007]。
来源: UIDatePicker类的参考
我build议定制一个UIPickerView
来使用两个组件,并使用从NSDateFormatter
检索的月份和年份符号填充行。
我在Swift中重写了Igor的答案:
class CLIVEDatePickerView: UIPickerView { enum Component: Int { case Month = 0 case Year = 1 } let LABEL_TAG = 43 let bigRowCount = 1000 let numberOfComponentsRequired = 2 let months = ["01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12"] var years: [String] { get { var years: [String] = [String]() for i in minYear...maxYear { years.append("\(i)") } return years; } } var bigRowMonthsCount: Int { get { return bigRowCount * months.count } } var bigRowYearsCount: Int { get { return bigRowCount * years.count } } var monthSelectedTextColor: UIColor? var monthTextColor: UIColor? var yearSelectedTextColor: UIColor? var yearTextColor: UIColor? var monthSelectedFont: UIFont? var monthFont: UIFont? var yearSelectedFont: UIFont? var yearFont: UIFont? let rowHeight: NSInteger = 44 /** Will be returned in user's current TimeZone settings **/ var date: NSDate { get { let month = self.months[selectedRowInComponent(Component.Month.rawValue) % months.count] let year = self.years[selectedRowInComponent(Component.Year.rawValue) % years.count] let formatter = NSDateFormatter() formatter.dateFormat = "MM yyyy" return formatter.dateFromString("\(month) \(year)")! } } var minYear: Int! var maxYear: Int! override init(frame: CGRect) { super.init(frame: frame) loadDefaultParameters() } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) loadDefaultParameters() } override func awakeFromNib() { super.awakeFromNib() loadDefaultParameters() } func loadDefaultParameters() { minYear = NSCalendar.currentCalendar().components(NSCalendarUnit.Year, fromDate: NSDate()).year maxYear = minYear! + 10 self.delegate = self self.dataSource = self monthSelectedTextColor = UIColor.blueColor() monthTextColor = UIColor.blackColor() yearSelectedTextColor = UIColor.blueColor() yearTextColor = UIColor.blackColor() monthSelectedFont = UIFont.boldSystemFontOfSize(17) monthFont = UIFont.boldSystemFontOfSize(17) yearSelectedFont = UIFont.boldSystemFontOfSize(17) yearFont = UIFont.boldSystemFontOfSize(17) } func setup(minYear: NSInteger, andMaxYear maxYear: NSInteger) { self.minYear = minYear if maxYear > minYear { self.maxYear = maxYear } else { self.maxYear = minYear + 10 } } func selectToday() { selectRow(todayIndexPath.row, inComponent: Component.Month.rawValue, animated: false) selectRow(todayIndexPath.section, inComponent: Component.Year.rawValue, animated: false) } var todayIndexPath: NSIndexPath { get { var row = 0.0 var section = 0.0 for cellMonth in months { if cellMonth == currentMonthName { row = Double(months.indexOf(cellMonth)!) row = row + Double(bigRowMonthsCount / 2) break } } for cellYear in years { if cellYear == currentYearName { section = Double(years.indexOf(cellYear)!) section = section + Double(bigRowYearsCount / 2) break } } return NSIndexPath(forRow: Int(row), inSection: Int(section)) } } var currentMonthName: String { get { let formatter = NSDateFormatter() let locale = NSLocale(localeIdentifier: "en_US") formatter.locale = locale formatter.dateFormat = "MM" return formatter.stringFromDate(NSDate()) } } var currentYearName: String { get { let formatter = NSDateFormatter() formatter.dateFormat = "yyyy" return formatter.stringFromDate(NSDate()) } } func selectedColorForComponent(component: NSInteger) -> UIColor { if component == Component.Month.rawValue { return monthSelectedTextColor! } return yearSelectedTextColor! } func colorForComponent(component: NSInteger) -> UIColor { if component == Component.Month.rawValue { return monthTextColor! } return yearTextColor! } func selectedFontForComponent(component: NSInteger) -> UIFont { if component == Component.Month.rawValue { return monthSelectedFont! } return yearSelectedFont! } func fontForComponent(component: NSInteger) -> UIFont { if component == Component.Month.rawValue { return monthFont! } return yearFont! } func titleForRow(row: Int, forComponent component: Int) -> String? { if component == Component.Month.rawValue { return self.months[row % self.months.count] } return self.years[row % self.years.count] } func labelForComponent(component: NSInteger) -> UILabel { let frame = CGRect(x: 0.0, y: 0.0, width: bounds.size.width, height: CGFloat(rowHeight)) let label = UILabel(frame: frame) label.textAlignment = NSTextAlignment.Center label.backgroundColor = UIColor.clearColor() label.userInteractionEnabled = false label.tag = LABEL_TAG return label } } extension CLIVEDatePickerView: UIPickerViewDelegate, UIPickerViewDataSource { func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int { return numberOfComponentsRequired } func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { if(component == Component.Month.rawValue) { return bigRowMonthsCount } else { return bigRowYearsCount } } func pickerView(pickerView: UIPickerView, widthForComponent component: Int) -> CGFloat { return self.bounds.size.width / CGFloat(numberOfComponentsRequired) } func pickerView(pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusingView view: UIView?) -> UIView { var selected = false if component == Component.Month.rawValue { let monthName = self.months[(row % self.months.count)] if monthName == currentMonthName { selected = true } } else { let yearName = self.years[(row % self.years.count)] if yearName == currentYearName { selected = true } } var returnView: UILabel if view?.tag == LABEL_TAG { returnView = view as! UILabel } else { returnView = labelForComponent(component) } returnView.font = selected ? selectedFontForComponent(component) : fontForComponent(component) returnView.textColor = selected ? selectedColorForComponent(component) : colorForComponent(component) returnView.text = titleForRow(row, forComponent: component) return returnView } func pickerView(pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat { return CGFloat(rowHeight) } }
我有一个懒惰的解决方法 – 我做了一个10×10黑色PNG。 然后,我用它作为一个scaletofill imageview的大小,以完美覆盖date列的面具。 我把阿尔法在0.75几乎没有显示该列。 用户清楚,看起来不错。
我正在使用一个简单的UIPickerView
与2个组件(月和年)。
并用每一行select来调用UIPickerViewDelegate
:
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component { //Today year and month NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init]; [dateFormat setDateFormat:@"yyyy"]; int year = [[dateFormat stringFromDate:[NSDate date]] intValue]; [dateFormat setDateFormat:@"MM"]; int month = [[dateFormat stringFromDate:[NSDate date]] intValue] - 1; //picker year and month int selectedYear = [[self.yearsArray objectAtIndex:[pickerView selectedRowInComponent:1]] intValue]; int selectedMonth = [pickerView selectedRowInComponent:0]; // if month in the past, change the month if (year == selectedYear && selectedMonth < month) { [pickerView selectRow:month inComponent:0 animated:YES]; } }
我刚刚重置的一天,当价值变化事件发生如下的月份的第一个月。 所以当用户select一天时,它会滚动回到第一位。 我使用以下select开始date(月份和年份)。
-(void) resetDay { NSDate *currentDate = [startDatePicker date]; NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; NSDateComponents *componentsYear = [gregorian components:(NSYearCalendarUnit| NSMonthCalendarUnit) fromDate:currentDate]; NSInteger yearNum = [ componentsYear year]; NSInteger monthNum = [componentsYear month]; NSLog(@"Month %d, Year %d", monthNum, yearNum); NSDateComponents *componentStartDate = [[NSDateComponents alloc] init]; [componentStartDate setDay:1]; [componentStartDate setMonth:monthNum]; [componentStartDate setYear:yearNum]; NSDate *startDate = [gregorian dateFromComponents:componentStartDate]; [startDatePicker setDate:startDate animated:YES]; [componentStartDate release]; [gregorian release]; }
为了select结束date(月份和年份),这个时间稍长一些,因为我想将当天设置为所选月份的31或30。
-(NSInteger) findDaysInYear { NSDate *currentDate = [NSDate date]; NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; NSDateComponents *componentsYear = [gregorian components:(NSYearCalendarUnit) fromDate:currentDate]; NSInteger yearNum = [ componentsYear year]; NSDateComponents *componentStartDate = [[NSDateComponents alloc] init]; [componentStartDate setDay:1]; [componentStartDate setMonth:1]; [componentStartDate setYear:yearNum]; NSDate *startDate = [gregorian dateFromComponents:componentStartDate]; NSLog(@"Start date set to %@", startDate); NSDateComponents *componentEndDate = [[NSDateComponents alloc] init]; [componentEndDate setDay:31]; [componentEndDate setMonth:12]; [componentEndDate setYear:yearNum]; NSDate *endDate = [gregorian dateFromComponents:componentEndDate]; NSLog(@"End date set to %@", endDate); NSUInteger unitFlags = NSDayCalendarUnit ; NSDateComponents *componentsDay = [gregorian components:unitFlags fromDate:startDate toDate:endDate options:0]; NSInteger days = [componentsDay day] +1; NSLog(@"Number of days in the year:%d, is %d", yearNum,days); [componentEndDate release]; [componentStartDate release]; [gregorian release]; if (days != 365 && days != 366) { return 366; } return days; } -(NSInteger) findDaysInMonth:(NSInteger) monthNum { NSInteger days = 30; switch (monthNum) { case 1: days = 31; break; case 2: if([self findDaysInYear] == 366) days = 29; else days = 28; break; case 3: days = 31; break; case 4: days = 30; break; case 5: days = 31; break; case 6: days = 30; break; case 7: days = 31; break; case 8: days = 31; break; case 9: days = 30; break; case 10: days = 31; break; case 11: days = 30; break; case 12: days = 31; break; default: break; } return days; } -(void) resetDay { NSDate *currentDate = [endDatePicker date]; NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; NSDateComponents *componentsYear = [gregorian components:(NSYearCalendarUnit| NSMonthCalendarUnit) fromDate:currentDate]; NSInteger yearNum = [ componentsYear year]; NSInteger monthNum = [componentsYear month]; NSDateComponents *componentStartDate = [[NSDateComponents alloc] init]; [componentStartDate setDay:[self findDaysInMonth:monthNum]]; [componentStartDate setMonth:monthNum]; [componentStartDate setYear:yearNum]; NSDate *startDate = [gregorian dateFromComponents:componentStartDate]; [endDatePicker setDate:startDate animated:YES]; [componentStartDate release]; [gregorian release]; }
您可以使用UICustomDatePicker仅显示月份和年份选项
https://github.com/Anandsan/UICustomDatePicker
@interface ViewController () @property (nonatomic, weak) IBOutlet UICustomDatePicker *customDatePicker; @end -(void) viewDidLoad { [super viewDidLoad]; self.customDatePicker.option = NSCustomDatePickerOptionLongMonth | NSCustomDatePickerOptionYear; self.customDatePicker.order = NSCustomDatePickerOrderMonthDayAndYear; } -(IBAction)didCustomDatePickerValueChanged:(id)sender { NSLog(@"%@",[(UICustomDatePicker *)sender currentDate]); }
参考屏幕
你可以很容易地隐藏date列这样的:
datePicker.subviews[0].subviews[0].subviews[1].hidden = true
请享用 :)