// // MOFSAddressPickerView.m // MOFSPickerManager // // Created by luoyuan on 16/8/31. // Copyright © 2016年 luoyuan. All rights reserved. // #import "MOFSAddressPickerView.h" #define UISCREEN_WIDTH [UIScreen mainScreen].bounds.size.width #define UISCREEN_HEIGHT [UIScreen mainScreen].bounds.size.height @interface MOFSAddressPickerView() @property (nonatomic, strong) NSXMLParser *parser; @property (nonatomic, strong) UIView *bgView; @property (nonatomic, strong) NSMutableArray *dataArr; @property (nonatomic, assign) NSInteger selectedIndex_province; @property (nonatomic, assign) NSInteger selectedIndex_city; @property (nonatomic, assign) NSInteger selectedIndex_area; @property (nonatomic, assign) BOOL isGettingData; @property (nonatomic, strong) void (^getDataCompleteBlock)(void); @property (nonatomic, strong) dispatch_semaphore_t semaphore; @property (nonatomic, assign) BOOL isSection; //0 < numberOfSection <= 3 @end @implementation MOFSAddressPickerView #pragma mark - setter - (void)setNumberOfSection:(NSInteger)numberOfSection { if (numberOfSection <= 0 || numberOfSection > 3) { _numberOfSection = 3; } else { _numberOfSection = numberOfSection; } dispatch_async(dispatch_get_main_queue(), ^{ [self reloadAllComponents]; }); } #pragma mark - create UI - (instancetype)initWithFrame:(CGRect)frame { self.semaphore = dispatch_semaphore_create(1); [self initToolBar]; [self initContainerView]; CGRect initialFrame; if (CGRectIsEmpty(frame)) { initialFrame = CGRectMake(0, self.toolBar.frame.size.height, UISCREEN_WIDTH, 216); } else { initialFrame = frame; } self = [super initWithFrame:initialFrame]; if (self) { self.backgroundColor = [UIColor whiteColor]; self.delegate = self; self.dataSource = self; [self initBgView]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [self getData]; dispatch_queue_t queue = dispatch_queue_create("my.current.queue", DISPATCH_QUEUE_CONCURRENT); dispatch_barrier_async(queue, ^{ dispatch_async(dispatch_get_main_queue(), ^{ [self reloadAllComponents]; }); }); }); } return self; } - (void)selectRow:(NSInteger)row inComponent:(NSInteger)component animated:(BOOL)animated { if (component >= self.numberOfComponents) { return; } [super selectRow:row inComponent:component animated:animated]; switch (component) { case 0: self.selectedIndex_province = row; self.selectedIndex_city = 0; self.selectedIndex_area = 0; if (self.numberOfSection > 1) { [self reloadComponent:1]; } if (self.numberOfSection > 2) { [self reloadComponent:2]; } break; case 1: self.selectedIndex_city = row; self.selectedIndex_area = 0; if (self.numberOfSection > 2) { [self reloadComponent:2]; } break; case 2: self.selectedIndex_area = row; break; default: break; } } - (void)initToolBar { self.toolBar = [[MOFSToolView alloc] initWithFrame:CGRectMake(0, 0, UISCREEN_WIDTH, 44)]; self.toolBar.backgroundColor = [UIColor whiteColor]; } - (void)initContainerView { self.containerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, UISCREEN_WIDTH, UISCREEN_HEIGHT)]; self.containerView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.4]; self.containerView.userInteractionEnabled = YES; [self.containerView addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(hiddenWithAnimation)]]; } - (void)initBgView { self.bgView = [[UIView alloc] initWithFrame:CGRectMake(0, UISCREEN_HEIGHT - self.frame.size.height - 44, UISCREEN_WIDTH, self.frame.size.height + self.toolBar.frame.size.height)]; } #pragma mark - Action - (void)showMOFSAddressPickerCommitBlock:(void(^)(NSString *address, NSString *zipcode))commitBlock cancelBlock:(void(^)(void))cancelBlock { if (self.numberOfSection <= 0 || self.numberOfComponents > 3) { self.numberOfSection = 3; } [self showWithAnimation]; __weak typeof(self) weakSelf = self; self.toolBar.cancelBlock = ^ { if (cancelBlock) { [weakSelf hiddenWithAnimation]; cancelBlock(); } }; self.toolBar.commitBlock = ^ { if (commitBlock) { [weakSelf hiddenWithAnimation]; if (weakSelf.dataArr.count > 0) { AddressModel *addressModel = weakSelf.dataArr[weakSelf.selectedIndex_province]; CityModel *cityModel; DistrictModel *districtModel; if (addressModel.list.count > 0) { cityModel = addressModel.list[weakSelf.selectedIndex_city]; } if (cityModel && cityModel.list.count > 0) { districtModel = cityModel.list[weakSelf.selectedIndex_area]; } NSString *address; NSString *zipcode; if (!cityModel || weakSelf.numberOfComponents == 1) { address = [NSString stringWithFormat:@"%@",addressModel.name]; zipcode = [NSString stringWithFormat:@"%@",addressModel.zipcode]; } else { if (!districtModel || weakSelf.numberOfComponents == 2) { address = [NSString stringWithFormat:@"%@-%@",addressModel.name,cityModel.name]; zipcode = [NSString stringWithFormat:@"%@-%@",addressModel.zipcode,cityModel.zipcode]; } else { address = [NSString stringWithFormat:@"%@-%@-%@",addressModel.name,cityModel.name,districtModel.name]; zipcode = [NSString stringWithFormat:@"%@-%@-%@",addressModel.zipcode,cityModel.zipcode,districtModel.zipcode]; } } commitBlock(address, zipcode); } } }; } - (void)showWithAnimation { [self addViews]; self.containerView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.0]; CGFloat height = self.bgView.frame.size.height; self.bgView.center = CGPointMake(UISCREEN_WIDTH / 2, UISCREEN_HEIGHT + height / 2); [UIView animateWithDuration:0.25 animations:^{ self.bgView.center = CGPointMake(UISCREEN_WIDTH / 2, UISCREEN_HEIGHT - height / 2); self.containerView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.4]; }]; } - (void)hiddenWithAnimation { CGFloat height = self.bgView.frame.size.height; [UIView animateWithDuration:0.25 animations:^{ self.bgView.center = CGPointMake(UISCREEN_WIDTH / 2, UISCREEN_HEIGHT + height / 2); self.containerView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.0]; } completion:^(BOOL finished) { [self hiddenViews]; }]; } - (void)addViews { UIWindow *window = [UIApplication sharedApplication].keyWindow; [window addSubview:self.containerView]; [window addSubview:self.bgView]; [self.bgView addSubview:self.toolBar]; [self.bgView addSubview:self]; } - (void)hiddenViews { [self removeFromSuperview]; [self.toolBar removeFromSuperview]; [self.bgView removeFromSuperview]; [self.containerView removeFromSuperview]; } #pragma mark - get data - (void)getData { self.isGettingData = YES; NSString *path = [[NSBundle mainBundle] pathForResource:@"province_data" ofType:@"xml"]; if (path == nil) { for (NSBundle *bundle in [NSBundle allFrameworks]) { path = [bundle pathForResource:@"province_data" ofType:@"xml"]; if (path != nil) { break; } } } if (path == nil) { self.isGettingData = NO; if (self.getDataCompleteBlock) { self.getDataCompleteBlock(); } return; } if (!_dataArr) { _dataArr = [NSMutableArray array]; } if (_dataArr.count != 0) { [_dataArr removeAllObjects]; } self.parser = [[NSXMLParser alloc] initWithData:[NSData dataWithContentsOfFile:path]]; self.parser.delegate = self; [self.parser parse]; } - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict { if ([elementName isEqualToString:@"province"]) { AddressModel *model = [[AddressModel alloc] initWithDictionary:attributeDict]; model.index = [NSString stringWithFormat:@"%lu", (unsigned long)self.dataArr.count]; [self.dataArr addObject:model]; } else if ([elementName isEqualToString:@"city"]) { CityModel *model = [[CityModel alloc] initWithDictionary:attributeDict]; model.index = [NSString stringWithFormat:@"%lu", (unsigned long)self.dataArr.lastObject.list.count]; [self.dataArr.lastObject.list addObject:model]; } else if ([elementName isEqualToString:@"district"]) { DistrictModel *model = [[DistrictModel alloc] initWithDictionary:attributeDict]; model.index = [NSString stringWithFormat:@"%lu", (unsigned long)self.dataArr.lastObject.list.lastObject.list.count]; [self.dataArr.lastObject.list.lastObject.list addObject: model]; } } - (void)parserDidEndDocument:(NSXMLParser *)parser { self.isGettingData = NO; if (self.getDataCompleteBlock) { self.getDataCompleteBlock(); } } #pragma mark - search - (void)searchType:(SearchType)searchType key:(NSString *)key block:(void(^)(NSString *result))block { dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER); NSString *valueName = @""; NSString *type = @""; if (searchType == SearchTypeAddressIndex) { valueName = @"index"; type = @"name"; } else if (searchType == SearchTypeZipcodeIndex) { valueName = @"index"; type = @"zipcode"; } else { valueName = searchType == SearchTypeAddress ? @"name" : @"zipcode"; type = searchType == SearchTypeAddress ? @"zipcode" : @"name"; } if (self.isGettingData || !self.dataArr || self.dataArr.count == 0) { __weak typeof(self) weakSelf = self; self.getDataCompleteBlock = ^{ if (block) { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ block([weakSelf searchByKey:key valueName:valueName type:type]); }); dispatch_semaphore_signal(weakSelf.semaphore); } }; } else { if (block) { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ block([self searchByKey:key valueName:valueName type:type]); }); dispatch_semaphore_signal(self.semaphore); } } } - (NSString *)searchByKey:(NSString *)key valueName:(NSString *)valueName type:(NSString *)type { if ([key isEqualToString:@""] || !key) { return @""; } NSArray *arr = [key componentsSeparatedByString:@"-"]; if (arr.count > 3) { return @"error0"; //最多只能输入省市区三个部分 } AddressModel *addressModel = (AddressModel *)[self searchModelInArr:_dataArr key:arr[0] type:type]; if (addressModel) { if (arr.count == 1) { //只输入了省份 return [addressModel valueForKey:valueName]; } CityModel *cityModel = (CityModel *)[self searchModelInArr:addressModel.list key:arr[1] type:type]; if (cityModel) { if (arr.count == 2) { //只输入了省份+城市 return [NSString stringWithFormat:@"%@-%@",[addressModel valueForKey:valueName],[cityModel valueForKey:valueName]]; } DistrictModel *districtModel = (DistrictModel *)[self searchModelInArr:cityModel.list key:arr[2] type:type]; if (districtModel) { return [NSString stringWithFormat:@"%@-%@-%@",[addressModel valueForKey:valueName],[cityModel valueForKey:valueName],[districtModel valueForKey:valueName]]; } else { return @"error3"; //输入区错误 } } else { return @"error2"; //输入城市错误 } } else { return @"error1"; //输入省份错误 } } - (NSObject *)searchModelInArr:(NSArray *)arr key:(NSString *)key type:(NSString *)type { NSObject *object; for (NSObject *obj in arr) { if ([key isEqualToString:[obj valueForKey:type]]) { object = obj; break; } } return object; } #pragma mark - UIPickerViewDelegate,UIPickerViewDataSource - (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView { return self.numberOfSection; } - (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component { AddressModel *addressModel; if (self.dataArr.count > 0) { addressModel = self.dataArr[self.selectedIndex_province]; } CityModel *cityModel; if (addressModel && addressModel.list.count > 0) { cityModel = addressModel.list[self.selectedIndex_city]; } if (self.dataArr.count != 0) { if (component == 0) { return self.dataArr.count; } else if (component == 1) { return addressModel == nil ? 0 : addressModel.list.count; } else if (component == 2) { return cityModel == nil ? 0 : cityModel.list.count; } else { return 0; } } else { return 0; } } - (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component { if (component == 0) { AddressModel *addressModel = self.dataArr[row]; return addressModel.name; } else if (component == 1) { AddressModel *addressModel = self.dataArr[self.selectedIndex_province]; CityModel *cityModel = addressModel.list[row]; return cityModel.name; } else if (component == 2) { AddressModel *addressModel = self.dataArr[self.selectedIndex_province]; CityModel *cityModel = addressModel.list[self.selectedIndex_city]; DistrictModel *districtModel = cityModel.list[row]; return districtModel.name; } else { return nil; } } - (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component { switch (component) { case 0: self.selectedIndex_province = row; self.selectedIndex_city = 0; self.selectedIndex_area = 0; if (self.numberOfSection > 1) { [pickerView reloadComponent:1]; [pickerView selectRow:0 inComponent:1 animated:NO]; } if (self.numberOfSection > 2) { [pickerView reloadComponent:2]; [pickerView selectRow:0 inComponent:2 animated:NO]; } break; case 1: self.selectedIndex_city = row; self.selectedIndex_area = 0; if (self.numberOfSection > 2) { [pickerView reloadComponent:2]; [pickerView selectRow:0 inComponent:2 animated:NO]; } break; case 2: self.selectedIndex_area = row; break; default: break; } } - (void)dealloc { } @end