iOS學習——UIPickerView的實現年月選擇器

来源:https://www.cnblogs.com/mukekeheart/archive/2018/03/15/8572628.html
-Advertisement-
Play Games

最近項目上需要用到一個選擇器,選擇器中的內容只有年和月,而在iOS系統自帶的日期選擇器UIDatePicker中卻只有四個選項如下,分別是時間(時分秒)、日期(年月日)、日期+時間(年月日時分)以及倒計時。其中並沒有我們所需要的只顯示年月的選擇器,在網上找了很多相關的資料,但是覺得都寫得過於麻煩。因 ...


  最近項目上需要用到一個選擇器,選擇器中的內容只有年和月,而在iOS系統自帶的日期選擇器UIDatePicker中卻只有四個選項如下,分別是時間(時分秒)、日期(年月日)、日期+時間(年月日時分)以及倒計時。其中並沒有我們所需要的只顯示年月的選擇器,在網上找了很多相關的資料,但是覺得都寫得過於麻煩。因此,為了滿足項目需求,自己用UIPickerView寫了一個只顯示年月的選擇器界面,同時還可以控制我們的顯示的最小時間。當然,如果要控制其他內容也都是可以的,無非就是在數據處理上多一些處理和控制。

typedef NS_ENUM(NSInteger, UIDatePickerMode) {
    UIDatePickerModeTime,           // Displays hour, minute, and optionally AM/PM designation depending on the locale setting (e.g. 6 | 53 | PM)
    UIDatePickerModeDate,           // Displays month, day, and year depending on the locale setting (e.g. November | 15 | 2007)
    UIDatePickerModeDateAndTime,    // Displays date, hour, minute, and optionally AM/PM designation depending on the locale setting (e.g. Wed Nov 15 | 6 | 53 | PM)
    UIDatePickerModeCountDownTimer, // Displays hour and minute (e.g. 1 | 53)
} __TVOS_PROHIBITED;

一 整體方案 

  在整個實現中分為兩個部分,首先是用一個基類來佈局我們選擇器的整體佈局,包括我們的選擇器的標題,取消、確定按鈕,蒙層等大框架的佈局,然後是子類在基類的基礎上添加UIPickerView來實現選擇器的基本功能以及數據載入和顯示。首先,我們來看一下整體的一個效果,點擊某個設定的控制項,然後彈出下圖所示的一個選擇器,選擇器的選項主要就是顯年月的信息:

 

二 基類佈局

  在上一部分說了,基類佈局主要是對整體的架構進行佈局,我們先看下有哪些內容,包括了背景蒙層視圖、彈出視圖(包含標題行(又包含取消按鈕、確定按鈕和標題)、分割線和選擇器),在子類中會進行一個整體的佈局,在 - (void)initUI 方法中進行佈局。

//
//  BaseView.h

#import <UIKit/UIKit.h>

#define kDatePicHeight 200  //選擇器的高度
#define kTopViewHeight 44   //取消 標題 確定 行高度

#define SCREEN_BOUNDS [UIScreen mainScreen].bounds
#define SCREEN_WIDTH [UIScreen mainScreen].bounds.size.width
#define SCREEN_HEIGHT [UIScreen mainScreen].bounds.size.height
@interface BaseView : UIView // 背景蒙層視圖 @property (nonatomic, strong) UIView *backgroundView; // 彈出視圖 @property (nonatomic, strong) UIView *alertView; // 標題行頂部視圖 @property (nonatomic, strong) UIView *topView; // 左邊取消按鈕 @property (nonatomic, strong) UIButton *leftBtn; // 右邊確定按鈕 @property (nonatomic, strong) UIButton *rightBtn; // 中間標題 @property (nonatomic, strong) UILabel *titleLabel; // 分割線視圖 @property (nonatomic, strong) UIView *lineView; /** 初始化子視圖 ,整體佈局*/ - (void)initUI; //以下三種方法在基類中的實現都是空白的,具體的效果在子類中重寫 /** 點擊背景遮罩圖層事件 */ - (void)didTapBackgroundView:(UITapGestureRecognizer *)sender; /** 取消按鈕的點擊事件 */ - (void)clickLeftBtn; /** 確定按鈕的點擊事件 */ - (void)clickRightBtn; @end

  具體的.m文件的實現代碼如下,進行摺疊了,需要的可以直接拷貝,在後面我們再 進行具體分析每一步的佈局和設置。

  1 //
  2 //  BaseView.m
  3 //  CJMobile
  4 //
  5 //  Created by mukekeheart on 2017/12/12.
  6 //  Copyright © 2017年 長江證券. All rights reserved.
  7 //
  8 
  9 #import "BaseView.h"
 10 
 11 @implementation BaseView
 12 
 13 - (void)initUI {
 14     self.frame = SCREEN_BOUNDS;
 15     // 背景遮罩圖層
 16     [self addSubview:self.backgroundView];
 17     // 彈出視圖
 18     [self addSubview:self.alertView];
 19     // 設置彈出視圖子視圖
 20     // 添加頂部標題欄
 21     [self.alertView addSubview:self.topView];
 22     // 添加左邊取消按鈕
 23     [self.topView addSubview:self.leftBtn];
 24     // 添加右邊確定按鈕
 25     [self.topView addSubview:self.rightBtn];
 26     // 添加中間標題按鈕
 27     [self.topView addSubview:self.titleLabel];
 28     // 添加分割線
 29     [self.topView addSubview:self.lineView];
 30 }
 31 
 32 #pragma mark - 背景遮罩圖層
 33 - (UIView *)backgroundView {
 34     if (!_backgroundView) {
 35         _backgroundView = [[UIView alloc]initWithFrame:SCREEN_BOUNDS];
 36         _backgroundView.backgroundColor = [UIColor blackColor] ;
 37         _backgroundView.alpha = 0.3f ;
 38         _backgroundView.userInteractionEnabled = YES;
 39         UITapGestureRecognizer *myTap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(didTapBackgroundView:)];
 40         [_backgroundView addGestureRecognizer:myTap];
 41     }
 42     return _backgroundView;
 43 }
 44 
 45 #pragma mark - 彈出視圖
 46 - (UIView *)alertView {
 47     if (!_alertView) {
 48         _alertView = [[UIView alloc]initWithFrame:CGRectMake(0, SCREEN_HEIGHT - kTopViewHeight - kDatePicHeight, SCREEN_WIDTH, kTopViewHeight + kDatePicHeight)];
 49         _alertView.backgroundColor = [UIColor whiteColor];
 50     }
 51     return _alertView;
 52 }
 53 
 54 #pragma mark - 頂部標題欄視圖
 55 - (UIView *)topView {
 56     if (!_topView) {
 57         _topView =[[UIView alloc]initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, kTopViewHeight + 0.5)];
 58         _topView.backgroundColor = [UIColor whiteColor];
 59     }
 60     return _topView;
 61 }
 62 
 63 #pragma mark - 左邊取消按鈕
 64 - (UIButton *)leftBtn {
 65     if (!_leftBtn) {
 66         _leftBtn = [UIButton buttonWithType:UIButtonTypeCustom];
 67         _leftBtn.frame = CGRectMake(5, 8, 60, 28);
 68         _leftBtn.backgroundColor = [UIColor clearColor];
 69         _leftBtn.layer.masksToBounds = YES;
 70         _leftBtn.titleLabel.font = [UIFont systemFontOfSize:17.0f];
 71         [_leftBtn setTitleColor:kGrayFontColor forState:UIControlStateNormal];
 72         [_leftBtn setTitle:@"取消" forState:UIControlStateNormal];
 73         [_leftBtn addTarget:self action:@selector(clickLeftBtn) forControlEvents:UIControlEventTouchUpInside];
 74     }
 75     return _leftBtn;
 76 }
 77 
 78 #pragma mark - 右邊確定按鈕
 79 - (UIButton *)rightBtn {
 80     if (!_rightBtn) {
 81         _rightBtn = [UIButton buttonWithType:UIButtonTypeCustom];
 82         _rightBtn.frame = CGRectMake(SCREEN_WIDTH - 65, 8, 60, 28);
 83         _rightBtn.backgroundColor = [UIColor clearColor];
 84         _rightBtn.layer.masksToBounds = YES;
 85         _rightBtn.titleLabel.font = [UIFont systemFontOfSize:17.0f];
 86         [_rightBtn setTitleColor:kBlueFontColor forState:UIControlStateNormal];
 87         [_rightBtn setTitle:@"確定" forState:UIControlStateNormal];
 88         [_rightBtn addTarget:self action:@selector(clickRightBtn) forControlEvents:UIControlEventTouchUpInside];
 89     }
 90     return _rightBtn;
 91 }
 92 
 93 #pragma mark - 中間標題按鈕
 94 - (UILabel *)titleLabel {
 95     if (!_titleLabel) {
 96         _titleLabel = [[UILabel alloc]initWithFrame:CGRectMake(65, 0, SCREEN_WIDTH - 130, kTopViewHeight)];
 97         _titleLabel.backgroundColor = [UIColor clearColor];
 98         _titleLabel.font = [UIFont systemFontOfSize:17.0f];
 99         _titleLabel.textColor = kBlackFontColor;
100         _titleLabel.textAlignment = NSTextAlignmentCenter;
101     }
102     return _titleLabel;
103 }
104 
105 #pragma mark - 分割線
106 - (UIView *)lineView {
107     if (!_lineView) {
108         _lineView = [[UIView alloc]initWithFrame:CGRectMake(0, kTopViewHeight, SCREEN_WIDTH, 0.5)];
109         _lineView.backgroundColor  = [UIColor colorWithRed:225 / 255.0 green:225 / 255.0 blue:225 / 255.0 alpha:1.0];
110         [self.alertView addSubview:_lineView];
111     }
112     return _lineView;
113 }
114 
115 #pragma mark - 點擊背景遮罩圖層事件
116 - (void)didTapBackgroundView:(UITapGestureRecognizer *)sender {
117     
118 }
119 
120 #pragma mark - 取消按鈕的點擊事件
121 - (void)clickLeftBtn {
122     
123 }
124 
125 #pragma mark - 確定按鈕的點擊事件
126 - (void)clickRightBtn {
127     
128 }
129 
130 @end
BaseView.m

  在BaseView.m中主要是對整體框架進行佈局,我們的控制項的位置都是通過絕對位置進行佈局的,所以需要修改的在話可以直接在對應的位置上進行修改,然後在BaseView.h中的註釋我們說過了,點擊背景遮罩圖層和取消、確定按鈕的點擊事件實現效果在基類中都是空白的,具體效果在子類中進行重寫來控制。而對於彈出視圖中的標題行(包含取消按鈕、確定按鈕和標題)、分割線和選擇器的具體佈局在這裡就不進行展開了,很簡單的部分,大家自行看一下代碼就OK了。

  下麵主要提兩個問題:一個是整體佈局的方法 - (void)initUI 的實現。這裡大家主要要註意的添加的層次,誰是誰的子視圖,一定要區分清楚。

- (void)initUI {
    self.frame = SCREEN_BOUNDS;
    // 背景遮罩圖層
    [self addSubview:self.backgroundView];
    // 彈出視圖
    [self addSubview:self.alertView];
    // 設置彈出視圖子視圖
    // 添加頂部標題欄
    [self.alertView addSubview:self.topView];
    // 添加左邊取消按鈕
    [self.topView addSubview:self.leftBtn];
    // 添加右邊確定按鈕
    [self.topView addSubview:self.rightBtn];
    // 添加中間標題按鈕
    [self.topView addSubview:self.titleLabel];
    // 添加分割線
    [self.topView addSubview:self.lineView];
}

  二是我們的背景蒙層和彈出視圖大家可以通過代碼看到蒙層遮罩背景的佈局是整個屏幕,那麼我們為什麼不直接在蒙層上添加彈出式圖呢?如果直接在蒙層上添加彈出式圖作為子視圖的話,我們的佈局相對會簡單很多,這裡涉及到一點就是子視圖的透明度是和父視圖保持一致的,如果直接將彈出視圖載入到蒙層遮罩視圖上,會導致彈出視圖的透明度也為0.3,所以彈出視圖不能直接加在蒙層遮罩視圖上,而是需要加在當前界面上。

- (UIView *)backgroundView {
    if (!_backgroundView) {
        _backgroundView = [[UIView alloc]initWithFrame:SCREEN_BOUNDS];
        _backgroundView.backgroundColor = [UIColor blackColor] ;
        _backgroundView.alpha = 0.3f ;
        _backgroundView.userInteractionEnabled = YES;
        UITapGestureRecognizer *myTap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(didTapBackgroundView:)];
        [_backgroundView addGestureRecognizer:myTap];
    }
    return _backgroundView;
}


    // 背景遮罩圖層
    [self addSubview:self.backgroundView];
    // 彈出視圖
    [self addSubview:self.alertView];

三 子類選擇器實現

  首先是我們的子類向外暴露的方法只有一個類方法,該方法主要是讓使用者提供選擇器的標題、最小日期、日期選擇完成後的操作等基本信息,方便我們對選擇器的數據和操作進行設置。對外暴露類方法也是避免使用者在使用時需要創建對象,比較麻煩,也避免一些不必要的問題。

//
//  CJYearMonthSelectedView.h

#import <UIKit/UIKit.h>
#import "BaseView.h"

//日期選擇完成之後的操作
typedef void(^BRDateResultBlock)(NSString *selectValue);

@interface CJYearMonthSelectedView : BaseView

//對外開放的類方法
+ (void)showDatePickerWithTitle:(NSString *)title minDateStr:(NSString *)minDateStr resultBlock:(BRDateResultBlock)resultBlock;

@end

   關於具體的子類的實現,還是先把所有代碼都貼上來,有點多,所以摺疊一下,後面對其中一些要點進行列出說明一下。還有取消、確定按鈕的點擊事件也都在這裡進行控制和實現,我們根據自己的需要進行這是就可以了,一般是在點擊確定按鈕的時候調用我們的BRDateResultBlock,實現日期選擇完成的操作。其中取消按鈕就直接沒有操作,dismiss當前界面,並註意要進行dealloc,創建的視圖要清除,避免記憶體泄露。蒙層背景點擊事件看需求,有的需要和取消一樣的效果,有的可能就無效果,自己添加即可。

  1 //  CJYearMonthSelectedView.m
  2 
  3 #import "CJYearMonthSelectedView.h"
  4 
  5 @interface CJYearMonthSelectedView () <UIPickerViewDelegate,UIPickerViewDataSource>
  6 @property (strong, nonatomic) UIPickerView *picker;    //選擇器
  7 @property (copy, nonatomic) NSString *title;
  8 @property (copy, nonatomic) NSString *minDateStr;
  9 @property (assign, nonatomic) BRDateResultBlock resultBlock;
 10 @property (copy, nonatomic) NSString *selectValue;   //選擇的值 
 11 @property (strong, nonatomic) NSMutableArray<NSString *> *data;
 12 
 13 @end
 14 
 15 @implementation CJYearMonthSelectedView
 16 
 17 + (void)showDatePickerWithTitle:(NSString *)title minDateStr:(NSString *)minDateStr resultBlock:(BRDateResultBlock)resultBlock{
 18     
 19     CJYearMonthSelectedView *datePicker = [[CJYearMonthSelectedView alloc] initWithTitle:title minDateStr:minDateStr resultBlock:resultBlock];
 20     [datePicker showWithAnimation:YES];
 21 }
 22 
 23 //初始化方法
 24 - (instancetype)initWithTitle:(NSString *)title minDateStr:(NSString *)minDateStr resultBlock:(BRDateResultBlock)resultBlock{
 25     if (self = [super init]) {
 26         _title = title;
 27         _minDateStr = minDateStr;
 28         _resultBlock = resultBlock;
 29         
 30         [self initUI];
 31     }
 32     
 33     return self;
 34 }
 35 
 36 //UI佈局,主要就是在彈出視圖上添加選擇器
 37 - (void)initUI{
 38     [super initUI];
 39     self.titleLabel.text = _title;
 40     // 添加時間選擇器
 41     [self.alertView addSubview:self.picker];
 42 }
 43 
 44 //選擇器的初始化和佈局
 45 - (UIPickerView *)picker{
 46     if (!_picker) {
 47         _picker = [[UIPickerView alloc] initWithFrame:CGRectMake(0, kTopViewHeight + 0.5, SCREEN_WIDTH, kDatePicHeight)];
 48 //        _picker.backgroundColor = [UIColor whiteColor];
 49         _picker.showsSelectionIndicator = YES;
 50         //設置代理
 51         _picker.delegate =self;
 52         _picker.dataSource =self;
 53     }
 54     return _picker;
 55 }
 56 
 57 //選擇器數據的載入,從設定的最小日期到當前月
 58 - (NSMutableArray<NSString *> *)data{
 59     if (!_data) {
 60         _data = [[NSMutableArray alloc] init];
 61         NSDate *currentDate = [NSDate date];
 62         NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
 63         [formatter setDateFormat:@"yyyy-MM"];
 64         NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
 65         NSDateComponents *lastMonthComps = [[NSDateComponents alloc] init];
 66         NSString *dateStr = [formatter stringFromDate:currentDate];
 67         NSInteger lastIndex = 0;
 68         NSDate *newdate;
 69         //迴圈獲取可選月份,從當前月份到最小月份
 70         while (!([dateStr compare:self.minDateStr] == NSOrderedAscending)) {
 71             [_data addObject:dateStr];
 72             lastIndex--;
 73             //獲取之前幾個月
 74             [lastMonthComps setMonth:lastIndex];
 75             newdate = [calendar dateByAddingComponents:lastMonthComps toDate:currentDate options:0];
 76             dateStr = [formatter stringFromDate:newdate];
 77         }
 78     }
 79     return _data;
 80 }
 81 
 82 #pragma mark - UIPickerView的數據和佈局,和tableview類似
 83 //返回多少列
 84 -(NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView{
 85     return 1;
 86 }
 87 
 88 //返回多少行
 89 - (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component{
 90     return self.data.count;
 91 }
 92 
 93 //每一行的數據
 94 -(NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component{
 95     return self.data[row];
 96 }
 97 
 98 //選中時的效果
 99 -(void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component{
100     self.selectValue = self.data[row];
101 }
102 
103 //返回高度
104 -(CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component{
105     return 35.0f;
106 }
107 
108 //返回寬度
109 -(CGFloat)pickerView:(UIPickerView *)pickerView widthForComponent:(NSInteger)component{
110     return ZYAppWidth;
111 }
112 
113 #pragma mark - 背景視圖的點擊事件
114 - (void)didTapBackgroundView:(UITapGestureRecognizer *)sender {
115     //    [self dismissWithAnimation:NO];
116 }
117 
118 #pragma mark - 彈出視圖方法
119 - (void)showWithAnimation:(BOOL)animation {
120     //1. 獲取當前應用的主視窗
121     UIWindow *keyWindow = [[UIApplication sharedApplication] keyWindow];
122     [keyWindow addSubview:self];
123     if (animation) {
124         // 動畫前初始位置
125         CGRect rect = self.alertView.frame;
126         rect.origin.y = SCREEN_HEIGHT;
127         self.alertView.frame = rect;
128         // 浮現動畫
129         [UIView animateWithDuration:0.3 animations:^{
130             CGRect rect = self.alertView.frame;
131             rect.origin.y -= kDatePicHeight + kTopViewHeight;
132             self.alertView.frame = rect;
133         }];
134     }
135 }
136 
137 #pragma mark - 關閉視圖方法
138 - (void)dismissWithAnimation:(BOOL)animation {
139     // 關閉動畫
140     [UIView animateWithDuration:0.2 animations:^{
141         CGRect rect = self.alertView.frame;
142         rect.origin.y += kDatePicHeight + kTopViewHeight;
143         self.alertView.frame = rect;
144         
145         self.backgroundView.alpha = 0;
146     } completion:^(BOOL finished) {
147         [self.leftBtn removeFromSuperview];
148         [self.rightBtn removeFromSuperview];
149         [self.titleLabel removeFromSuperview];
150         [self.lineView removeFromSuperview];
151         [self.topView removeFromSuperview];
152         [self.picker removeFromSuperview];
153         [self.alertView removeFromSuperview];
154         [self.backgroundView removeFromSuperview];
155         [self removeFromSuperview];
156         
157         self.leftBtn = nil;
158         self.rightBtn = nil;
159         self.titleLabel = nil;
160         self.lineView = nil;
161         self.topView = nil;
162         self.picker = nil;
163         self.alertView = nil;
164         self.backgroundView = nil;
165     }];
166 }
167 
168 #pragma mark - 取消按鈕的點擊事件
169 - (void)clickLeftBtn {
170     [self dismissWithAnimation:YES];
171 }
172 
173 #pragma mark - 確定按鈕的點擊事件
174 - (void)clickRightBtn {
175     NSLog(@"點擊確定按鈕後,執行block回調");
176     [self dismissWithAnimation:YES];
177     if (_resultBlock) {
178         _resultBlock(_selectValue);
179     }
180 }
181 
182 @end
CJYearMonthSelectedView.m

  這裡面跟著流程看其實很簡單哈,主要需要說明的一點就是UIPickerView的用法,UIPickerView其實和UITableView很類似,在初始化的時候需要設置其數據代理和視圖代理(UIPickerViewDelegate,UIPickerViewDataSource),然後通過這兩個代理進內容、行數、列數的控制。

- (UIPickerView *)picker{
    if (!_picker) {
        _picker = [[UIPickerView alloc] initWithFrame:CGRectMake(0, kTopViewHeight + 0.5, SCREEN_WIDTH, kDatePicHeight)];
        _picker.showsSelectionIndicator = YES;
        //設置UIPickerView的代理
        _picker.delegate =self;
        _picker.dataSource =self;
    }
    return _picker;
}
#pragma mark - UIPickerView
//返回多少列
-(NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView{
    return 1;
}

//返回多少行
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component{
    return self.data.count;
}

//每一行的數據
-(NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component{
    return self.data[row];
}

//選中時的效果
-(void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component{
    self.selectValue = self.data[row];
}

//返回高度
-(CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component{
    return 35.0f;
}

//返回寬度
-(CGFloat)pickerView:(UIPickerView *)pickerView widthForComponent:(NSInteger)component{
    return ZYAppWidth;
}

  關於數據的控制可以根據我們的需要進行設定,行數和列數也是根據我們的需求來進行控制。下麵主要就是說一下如何獲取年月這樣的數據,主要是用到了NSDateComponents 的直接獲取一個月前的信息,然後通過將NSCalendar將NSDateComponents轉化為日期Date,最後將Date轉化為我們需要的格式的數據。

//數據獲取
- (NSMutableArray<NSString *> *)data{
    if (!_data) {
        _data = [[NSMutableArray alloc] init];
        //當前日期時間
        NSDate *currentDate = [NSDate date];
        //設定數據格式為xxxx-mm
        NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
        [formatter setDateFormat:@"yyyy-MM"];
        //通過日曆可以直接獲取前幾個月的日期,所以這裡直接用該類的方法進行迴圈獲取數據
        NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
        NSDateComponents *lastMonthComps = [[NSDateComponents alloc] init];
        NSString *dateStr = [formatter stringFromDate:currentDate];
        NSInteger lastIndex = 0;
        NSDate *newdate;
        //迴圈獲取可選月份,從當前月份到最小月份,直接用字元串的比較來判斷是否大於設定的最小日期
        while (!([dateStr compare:self.minDateStr] == NSOrderedAscending)) {
            [_data addObject:dateStr];
            lastIndex--;
            //獲取之前n個月, setMonth的參數為正則向後,為負則表示之前
            [lastMonthComps setMonth:lastIndex];
            newdate = [calendar dateByAddingComponents:lastMonthComps toDate:currentDate options:0];
            dateStr = [formatter stringFromDate:newdate];
        }
    }
    return _data;
}

 四 使用方法

  關於自己做的這個在使用上就非常簡單了,我們的子類向外就暴露了一個類方法,所以我們再需要彈出選擇器的地方調用該方法就可以了。

- (void) btnPress:(UIButton *)sender{
    if (sender.tag == 200) { //導出 按鈕
        [CJYearMonthSelectedView showDatePickerWithTitle:@"選擇月份" minDateStr:@"2017-10" resultBlock:^(NSString *selectValue) {
            //選擇完成後的操作
            NSLog(@"selected month is %@", selectValue);
        }];
    } else {
        
    }
}

   以上就是使用UIPickerView自定義一個年月的選擇器,包括最初的的完整的界面代碼和具體的選擇器的創建和佈局,以及我們的數據處理。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 簡要:本系列文章講會對expo進行全面的介紹,本人從2017年6月份接觸expo以來,對expo的研究斷斷續續,一路走來將近10個月,廢話不多說,接下來你看到內容,講全部來與官網 我猜去全部機翻+個人修改補充+demo測試的形式,對expo進行一次大補血!歡迎加入expo興趣學習交流群:597732 ...
  • 簡要:本系列文章講會對expo進行全面的介紹,本人從2017年6月份接觸expo以來,對expo的研究斷斷續續,一路走來將近10個月,廢話不多說,接下來你看到內容,講全部來與官網 我猜去全部機翻+個人修改補充+demo測試的形式,對expo進行一次大補血!歡迎加入expo興趣學習交流群:597732 ...
  • 簡要:本系列文章講會對expo進行全面的介紹,本人從2017年6月份接觸expo以來,對expo的研究斷斷續續,一路走來將近10個月,廢話不多說,接下來你看到內容,講全部來與官網 我猜去全部機翻+個人修改補充+demo測試的形式,對expo進行一次大補血!歡迎加入expo興趣學習交流群:597732 ...
  • 最近在做項目的時候遇到了一個需求,那就是要對一張圖片做處理,實現邊緣模糊過渡。 苦思良久,最終用了以下的方法。 1、構成一張圖片的是ARGB,我們可以直接把這整張圖片的ARGB取出來,然後改變圖片的A,也就是透明度。 以上我們便獲得了圖片的ARGB值,而我們只需要改變透明度A。 2、我們可以用 最後 ...
  • 普通廣播: 1.在AndroidManifest.xml中配置廣播接收器: <receiver android:name="com.example.toast.MyBroadReceiver" > <intent-filter> <action android:name="MyBroad" /> < ...
  • 對於這個問題,今天折騰了一下午,不是說我不懂得怎麼調用,而是我用了看似正確的調用方式,而其實這是一個坑。 我用了下麵這種方式: 用這種方式是正確的,必須要將context轉換為Activity。 但是由於我是在一個特殊的場景裡面使用的,導致activity的onActivityResult沒有被回調 ...
  • 一、Audio Toolbox 1.使用代碼 import AudioServicesPlaySystemSound(1106); 2.如果想用自己的音頻文件創建系統聲音來播放的同學可以參考如下代碼。 //Get the filename of the sound file: NSString pa ...
  • 簡要:本系列文章講會對expo進行全面的介紹,本人從2017年6月份接觸expo以來,對expo的研究斷斷續續,一路走來將近10個月,廢話不多說,接下來你看到內容,講全部來與官網 我猜去全部機翻+個人修改補充+demo測試的形式,對expo進行一次大補血!歡迎加入expo興趣學習交流群:597732 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...