iOS三級聯(lián)動選擇器的實現(xiàn)代碼示例
無聊ing...封裝個省市區(qū)三級聯(lián)動選擇器的小demo吧。
上家公司的三級地區(qū)選擇器的數(shù)據(jù)是一次性通過網(wǎng)絡請求就能獲取到的,但新東家這邊并不是,而是先選擇了省獲取省的Id再去獲取市,再通過得到市的Id獲取區(qū)域,show code之前,先看下需要考慮的幾個點:
1)怎么設(shè)置默認值,關(guān)鍵代碼
[self.pickerView selectRow:xxx inComponent:xxx animated:YES];
2)怎么讓三級之間聯(lián)動 ,關(guān)鍵代碼
[self pickerView:self.pickerView didSelectRow:0 inComponent:0 ];//聯(lián)動輪子1 必須得本輪有數(shù)據(jù)后觸發(fā)否則crash
先看下效果圖

關(guān)于設(shè)置默認值,三級聯(lián)動,用UIPickView的話就是有3個輪子(component),首先我們要想到,第一次向后臺發(fā)起請求,我們只能獲取到第0個component的數(shù)據(jù),只有當你滾動輪子的時候才會獲取到省的Id發(fā)起請求來獲得該省的市的數(shù)據(jù),也就是第1個component的數(shù)據(jù),依此類推,滾動第1個component發(fā)起請求來獲取第2個component的數(shù)據(jù),因此,pickView的監(jiān)聽輪子滾動的代理起了重要作用
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component;
我們通過接口獲取第0個component的數(shù)據(jù),這邊是后臺規(guī)定的使用id=0,獲取到以后,默認選中第0個component的第0個row并主動調(diào)用觸發(fā)pick的輪子滾動代理來聯(lián)動第1個component【要在獲取數(shù)據(jù)成功后再執(zhí)行這部操作,因此放在數(shù)據(jù)請求成功的回調(diào)內(nèi)】,代碼為
[self pickerView:self.pickerView didSelectRow:0 inComponent:0 ];
在各輪子滾動過程中,用一個中間值
_selectedRow0記錄下第0個component的選中行
_selectedRow1記錄下第1個component的選中行
_selectedRow2記錄下第2個component的選中行,
這里需要記住,滾動某個輪子只能對它后面的輪子產(chǎn)生影響,所以當滾動第0個component的時候使_selectedRow1,_selectedRow2均置為0,這里注意,上面提到的
默認選中第0個component的第0個row并主動調(diào)用觸發(fā)pick的輪子滾動代理來聯(lián)動第1個component
要先將輪子上的數(shù)據(jù)渲染好,設(shè)置好默認值才能主動調(diào)用監(jiān)聽輪子滾動的代理,否則會導致崩潰,另一個防崩潰的點如下圖

發(fā)現(xiàn)第三級沒數(shù)據(jù)的時候,如果你在代碼里沒加【安全措施】,那也會導致崩潰,要在請求到第三級的數(shù)據(jù)后做下判斷,如果個數(shù)為空,將該級對應的數(shù)據(jù)源置為nil。(其它兩級的輪子最好也加判斷)
最后,由于這是個封裝的類,最終要得到選中的詳細信息,可通過代理或block傳值給controller。
又是你們最喜歡show code環(huán)節(jié):
.h文件
#import <UIKit/UIKit.h> //定制代理協(xié)議 @protocol ZLMAddressPickerViewDelegate <NSObject> - (void)addressPickerViewDidSelected:(NSString *)areaName;//點擊上方完成按鈕的代理傳回拼接好的選中地址 - (void)addressPickerViewDidClose;//點擊關(guān)閉代理 @end @interface ZLMAddressPickerView : UIView @property (weak, nonatomic) id<ZLMAddressPickerViewDelegate> delegate; @end
.m文件
#import "ZLMAddressPickerView.h"
#import "AFHttpUtils.h"
#import "AreaModel.h"
@interface ZLMAddressPickerView () <UIPickerViewDataSource, UIPickerViewDelegate>
@property (strong, nonatomic) UIPickerView *pickerView;
@property (strong, nonatomic) AreaModel *provBridge;
@property (strong, nonatomic) AreaModel *cityBridge;
@property (strong, nonatomic) AreaModel *areaBridge;
@property (copy, nonatomic) NSArray<Area *> * provDataArr;//省數(shù)組
@property (copy, nonatomic) NSArray<Area *> * cityDataArr;//市數(shù)組
@property (copy, nonatomic) NSArray<Area *> * areaDataArr;//區(qū)數(shù)組
@end
@implementation ZLMAddressPickerView
{
NSInteger _selectRow0;//記錄第0個輪子的選擇行
NSInteger _selectRow1;
NSInteger _selectRow2;
NSString *_areaString;//最后要傳回的詳細地址拼接字符串
Area *_proModel;//記錄下選中省的數(shù)據(jù)
Area *_cityModel;
Area *_areaModel;
}
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self setup];
}
return self;
}
- (void)setup {
_selectRow0 = 0;
_selectRow1 = 0;
_selectRow2 = 0;
self.backgroundColor = [UIColor whiteColor];
UIToolbar *toolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.bounds), 44)];
toolbar.backgroundColor = [UIColor whiteColor];
[self addSubview:toolbar];
UIBarButtonItem *closeItem = [[UIBarButtonItem alloc] initWithTitle:@"關(guān)閉" style:UIBarButtonItemStylePlain target:self action:@selector(selectAddressClose)];
UIBarButtonItem *completeItem = [[UIBarButtonItem alloc] initWithTitle:@"完成" style:UIBarButtonItemStylePlain target:self action:@selector(selectAddressComplete)];
UIBarButtonItem *spaceItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
toolbar.items = @[closeItem, spaceItem, completeItem];
self.pickerView.frame = CGRectMake(0, 44, CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds) - 44);
[self addSubview:self.pickerView];
[self downloadProv];
}
#pragma mark - http methods
/*省*/
- (void)downloadProv {
NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithDictionary: @{@"id":@(0)} ];
[AFHttpUtils sendPostTaskWithUrl:[NSString stringWithFormat:@"%@/app/member/area",BASE_DOMAIN_URL] paramenters:dic successHandle:^(NSURLSessionDataTask *task, id responseObject) {
NSLog(@"PROV:%@",responseObject);
self.provBridge = [AreaModel mj_objectWithKeyValues:responseObject];
if (self.provBridge.error_code==0) {
self.provDataArr=self.provBridge.data;
[self pickerView:self.pickerView didSelectRow:0 inComponent:0 ];//聯(lián)動輪子1 必須得本輪有數(shù)據(jù)后才能觸發(fā)didselect
[self.pickerView reloadAllComponents];
}
} errorHandle:^(NSError *error) {
}];
}
/*市*/
- (void)downloadCityWithId:(NSInteger)provId {
NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithDictionary: @{@"id":@(provId)} ];
[AFHttpUtils sendPostTaskWithUrl:[NSString stringWithFormat:@"%@/app/member/area",BASE_DOMAIN_URL] paramenters:dic successHandle:^(NSURLSessionDataTask *task, id responseObject) {
NSLog(@"CITY:%@",responseObject);
self.cityBridge = [AreaModel mj_objectWithKeyValues:responseObject];
if (self.cityBridge.error_code==0) {
self.cityDataArr=self.cityBridge.data;
[self.pickerView reloadComponent:1];
[self.pickerView selectRow:0 inComponent:1 animated:YES];//默認選擇row0
[self pickerView:self.pickerView didSelectRow:0 inComponent:1 ];//聯(lián)動輪子2 必須得本輪有數(shù)據(jù)后才能觸發(fā)didselect
_cityModel = self.cityDataArr[_selectRow1];
[self downloadAreaWithId:_cityModel.area_id];
}
} errorHandle:^(NSError *error) {
}];
}
/*區(qū)*/
- (void)downloadAreaWithId:(NSInteger)cityId {
NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithDictionary: @{@"id":@(cityId)} ];
[AFHttpUtils sendPostTaskWithUrl:[NSString stringWithFormat:@"%@/app/member/area",BASE_DOMAIN_URL] paramenters:dic successHandle:^(NSURLSessionDataTask *task, id responseObject) {
NSLog(@"AREA:%@",responseObject);
self.areaBridge = [AreaModel mj_objectWithKeyValues:responseObject];
if (self.areaBridge.error_code==0&&self.areaBridge.data.count>0) {
self.areaDataArr=self.areaBridge.data;
}else{
self.areaDataArr=nil;
}
[self.pickerView reloadComponent:2];
[self.pickerView selectRow:0 inComponent:2 animated:YES];
[self pickerView:self.pickerView didSelectRow:0 inComponent:2 ];
} errorHandle:^(NSError *error) {
}];
}
#pragma mark - events response
- (void)selectAddressComplete {
[self.delegate addressPickerViewDidSelected:_areaString];
}
- (void)selectAddressClose {
[self.delegate addressPickerViewDidClose];
}
#pragma mark - UIPickerViewDataSource
//確定picker的輪子個數(shù)
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {
return 3;
}
//確定picker的每個輪子的item數(shù)
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
if (component==0) {
return self.provDataArr.count;
}else if(component==1){
return self.cityDataArr.count;
}else{
return self.areaDataArr.count;
}
}
- (CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component{
return 36;
}
//確定每個輪子的每一項顯示什么內(nèi)容
- (NSAttributedString *)pickerView:(UIPickerView *)pickerView attributedTitleForRow:(NSInteger)row forComponent:(NSInteger)component{
NSDictionary * attrDic = @{NSForegroundColorAttributeName:[UIColor blackColor],
NSFontAttributeName:[UIFont systemFontOfSize:12]};
Area *area;
if (component==0) {
area = self.provDataArr[row];
}else if(component==1){
area = self.cityDataArr[row];
}else{
area = self.areaDataArr[row];
}
NSAttributedString * attrString = [[NSAttributedString alloc] initWithString:area.name
attributes:attrDic];
return attrString;
}
//監(jiān)聽輪子的移動
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
if (component==0) {
_selectRow0 = [pickerView selectedRowInComponent:0];
_selectRow1 = 0;
_selectRow2 = 0;
_proModel = self.provDataArr[_selectRow0];
[self downloadCityWithId:_proModel.area_id];
}else if(component==1){
_selectRow1 = [pickerView selectedRowInComponent:1];
_selectRow2 = 0;
_cityModel = self.cityDataArr[_selectRow1];
[self downloadAreaWithId:_cityModel.area_id];
}else{
_selectRow2 = [pickerView selectedRowInComponent:2];
if (self.areaDataArr&&self.areaDataArr.count>0) {
_areaModel = self.areaDataArr[_selectRow2];
}else{
_areaModel = nil;
}
}
if(_areaModel==nil){
_areaString = [NSString stringWithFormat:@"%@ %@",_proModel.name,_cityModel.name];
}else{
_areaString = [NSString stringWithFormat:@"%@ %@ %@",_proModel.name,_cityModel.name,_areaModel.name];
}
}
#pragma mark - getters and setters
- (UIPickerView *)pickerView {
if (_pickerView == nil) {
_pickerView = [[UIPickerView alloc] init];
_pickerView.delegate = self;
_pickerView.dataSource = self;
}
return _pickerView;
}
@end
最后在controller中調(diào)用
(1)導入
#import "ZLMAddressPickerView.h"
(2)定義一個對象并遵守代理協(xié)議
@property (strong, nonatomic) ZLMAddressPickerView *addressPickerView;
(3)懶加載生成對象(個人習慣)
- (ZLMAddressPickerView *)addressPickerView {
if (!_addressPickerView) {
_addressPickerView = [[ZLMAddressPickerView alloc] initWithFrame:CGRectMake(0, SCREEN_HEIGHT-244-64, SCREEN_WIDTH, 244)];
_addressPickerView.delegate = self;
}
return _addressPickerView;
}
(4)在點擊跳出三級聯(lián)動選擇器的地方
[self.view addSubview:self.addressPickerView];
(5)別忘了實現(xiàn)代理
#pragma mark - ZLMAddressPickerViewDelegate
- (void)addressPickerViewDidSelected:(NSString *)areaName {
self.areaLabel.text = areaName;//將傳回的詳細地址字符串賦值
[self addressPickerViewDidClose];
}
- (void)addressPickerViewDidClose {
[self.addressPickerView removeFromSuperview];
}
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
iOS的UI開發(fā)中UITabBarControlle的基本使用教程
這篇文章主要介紹了iOS的UI開發(fā)中UITabBarControlle的基本使用教程,代碼基于傳統(tǒng)的Objective-C,需要的朋友可以參考下2015-12-12
iOS中給自定義tabBar的按鈕添加點擊放大縮小的動畫效果
這篇文章主要介紹了iOS中給自定義tabBar的按鈕添加點擊放大縮小的動畫效果的相關(guān)資料,非常不錯,具有參考解決價值,需要的朋友可以參考下2016-11-11
Flutter?ScrollController滾動監(jiān)聽及控制示例詳解
這篇文章主要為大家介紹了Flutter?ScrollController滾動監(jiān)聽及控制示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-11-11

