UIDatePicker select Month and Year UIDatePicker select Month and Year ios ios

UIDatePicker select Month and Year


Here is a solution to get the same effect. For using this snippet of code you should replace UIPickerView to CDatePickerViewEx in nib file in "Custom class" of "Indentity inspector".

.h file

#import <UIKit/UIKit.h>@interface CDatePickerViewEx : UIPickerView <UIPickerViewDelegate, UIPickerViewDataSource> @property (nonatomic, strong, readonly) NSDate *date;-(void)selectToday;@end

.m file

#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 CDatePickerViewExconst 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


Yeah, you probably want to just make your own picker. You don't have to subclass it or anything, though; just use a generic UIPickerView and return appropriate values from your UIPickerViewDelegate/UIPickerViewDataSource methods.


I rewrote Igor's answer in Swift:

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