最近項目上需要用到一個選擇器,選擇器中的內容只有年和月,而在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 @endBaseView.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 @endCJYearMonthSelectedView.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自定義一個年月的選擇器,包括最初的的完整的界面代碼和具體的選擇器的創建和佈局,以及我們的數據處理。