ios UIDatePicker 选择月份和年份

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3348247/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 17:28:54  来源:igfitidea点击:

UIDatePicker select Month and Year

iosobjective-cuikituipickerviewuidatepicker

提问by Dave

I need a UIDatePickerfor selecting Month and Year only. I checked the class reference documents. Looks like UIDatePickeris a UIView. I imagined UIPickerViewmay be a sub view and I can hide the component if I can grab it. But no. That was not possible. Do I have to create my own custom picker then? Any ideas?

我只需要一个UIDatePicker来选择月份和年份。我检查了类参考文件。看起来UIDatePicker是一个UIView. 我想UIPickerView可能是一个子视图,如果我能抓住它,我可以隐藏它。但不是。那是不可能的。那么我是否必须创建自己的自定义选择器?有任何想法吗?

采纳答案by Noah Witherspoon

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

是的,您可能只想制作自己的选择器。但是,您不必将其子类化或进行任何操作;只需使用泛型UIPickerView并从您的UIPickerViewDelegate/UIPickerViewDataSource方法返回适当的值。

回答by Igor

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

这是获得相同效果的解决方案。要使用这段代码,您应该在“UIPickerView身份CDatePickerViewEx检查器”的“自定义类”中的 nib 文件中替换为。

.h file

.h 文件

#import <UIKit/UIKit.h>

@interface CDatePickerViewEx : UIPickerView <UIPickerViewDelegate, UIPickerViewDataSource> 

@property (nonatomic, strong, readonly) NSDate *date;
-(void)selectToday;

@end

.m file

.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

回答by RossP

I rewrote Igor's answer in Swift:

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

}

回答by Justin

No, this cannot be done using the stock UIDatePicker.

,这不能使用股票来完成UIDatePicker

UIDatePickerModeDate

The date picker displays months, days of the month, and years. The exact order of these items depends on the locale setting. An example of this mode is [ November | 15 | 2007 ].

UIDatePickerModeDate

日期选择器显示月份、月份的日期和年份。这些项目的确切顺序取决于区域设置。这种模式的一个例子是 [ 十一月 | 15 | 2007 年]。

Source: UIDatePicker class reference

来源:UIDatePicker 类参考

I recommend customizing a UIPickerViewto use two components and populating its rows with month and year symbols retrieved from NSDateFormatter.

我建议自定义 aUIPickerView以使用两个组件,并使用从NSDateFormatter.

回答by George

Rewritten answerof RossPin Swift 4:

在 Swift 4 中重写了RossP 的答案

import Foundation

@objc class ShortDatePickerView: 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: Date {
        get {
            let month = self.months[selectedRow(inComponent: Component.Month.rawValue) % months.count]
            let year = self.years[selectedRow(inComponent: Component.Year.rawValue) % years.count]
            let formatter = DateFormatter()
            formatter.dateFormat = "MM yyyy"
            return formatter.date(from: "\(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 = Calendar.current.dateComponents([.year], from: Date()).year
        maxYear = minYear! + 10

        self.delegate = self
        self.dataSource = self

        monthSelectedTextColor = .blue
        monthTextColor = .black

        yearSelectedTextColor = .blue
        yearTextColor = .black

        monthSelectedFont = .boldSystemFont(ofSize: 17)
        monthFont = .boldSystemFont(ofSize: 17)

        yearSelectedFont = .boldSystemFont(ofSize: 17)
        yearFont = .boldSystemFont(ofSize: 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.index(of: cellMonth)!)
                    row = row + Double(bigRowMonthsCount / 2)
                    break
                }
            }

            for cellYear in years {
                if cellYear == currentYearName {
                    section = Double(years.index(of: cellYear)!)
                    section = section + Double(bigRowYearsCount / 2)
                    break
                }
            }

            return NSIndexPath(row: Int(row), section: Int(section))
        }
    }

    var currentMonthName: String {
        get {
            let formatter = DateFormatter()
            let locale = Locale.init(identifier: "en_US")
            formatter.locale = locale
            formatter.dateFormat = "MM"
            return formatter.string(from: Date())
        }
    }

    var currentYearName: String {
        get {
            let formatter = DateFormatter()
            formatter.dateFormat = "yyyy"
            return formatter.string(from: Date())
        }
    }


    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 = .center
        label.backgroundColor = .clear
        label.isUserInteractionEnabled = false
        label.tag = LABEL_TAG
        return label
    }
}

extension ShortDatePickerView: 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, reusing 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: component)
        }

        returnView.font = selected ? selectedFontForComponent(component: component) : fontForComponent(component: component)
        returnView.textColor = selected ? selectedColorForComponent(component: component) : colorForComponent(component: component)

        returnView.text = titleForRow(row: row, forComponent: component)

        return returnView
    }

    func pickerView(_ pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat {
        return CGFloat(rowHeight)
    }

    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return 2
    }
}

回答by Mischa

I have a lazy workaround-- I made a 10x10 black png. I then used that as a mask with a scaletofill imageview sized to cover the dates column perfectly. I put the alpha at 0.75 to barely show that column. It is clear to the user and looks decent.

我有一个懒惰的解决方法——我制作了一个 10x10 的黑色 png。然后我将它用作一个带有 scaletofill imageview 的遮罩,其大小可以完美地覆盖日期列。我将 alpha 设为 0.75 以勉强显示该列。这对用户来说很清楚,看起来不错。

回答by Gabriel.Massana

I'm using a simple UIPickerViewwith 2 components (months and years).

我正在使用一个简单UIPickerView的 2 个组件(月和年)。

And calling the UIPickerViewDelegatewith every row selection:

并在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];
    }
}

回答by Gamma-Point

I just reset the day to first of the month when the value change event happens as below. So When the user selects a day, it scrolls back to 1st. I use following for selecting Start date (month & year).

当值更改事件发生时,我只是将日期重置为每月的第一天,如下所示。因此,当用户选择一天时,它会滚动回第 1 天。我使用以下来选择开始日期(月和年)。

-(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];
}

For selecting the End Date (month & year) it is little bit longer, because I wanted to set the day to 31st or 30th of the month selected.

对于选择结束日期(月份和年份),它有点长,因为我想将日期设置为所选月份的 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];
}

回答by anand sankaran

You can use UICustomDatePicker to show only the month and year option

您可以使用 UICustomDatePicker 仅显示月份和年份选项

https://github.com/Anandsan/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]);

}

Refer the Screen

参考屏幕

回答by Ali

You can use the open source library named

您可以使用名为的开源库

AKMonthYearPickerView

AKMonthYearPickerView

import AKMonthYearPickerView

AKMonthYearPickerView.sharedInstance.show(vc: viewController, doneHandler: doneHandler, completetionalHandler: completetionalHandler)

https://github.com/ali-cs/AKMonthYearPickerView

https://github.com/ali-cs/AKMonthYearPickerView

to install it using pods,

使用 pods 安装它,

pod 'AKMonthYearPickerView' 

to customize previous years limit and bar color

自定义往年限额和条形颜色

AKMonthYearPickerView.sharedInstance.barTintColor =   UIColor.blue

AKMonthYearPickerView.sharedInstance.previousYear = 4

enter image description here

在此处输入图片说明