導(dǎo)讀
目前大多數(shù)APP的地址選擇是用系統(tǒng)的picker View,也不乏用tableview自定義的.
這里分享一個(gè)高仿京東的地址選擇給大家.
源碼地址:https://github.com/HelloYeah/ChooseLocation
歡迎大家checkout,Star...
下面是京東收貨地址的一些交互以及代碼思路分析
1.剛打開選擇地址視圖時(shí),底部ScrollView的滾動(dòng)范圍只有一屏寬.
2.點(diǎn)擊某個(gè)省時(shí),增加對(duì)應(yīng)的市級(jí)列表,底部ScrollView橫向滾動(dòng)區(qū)域增加一屏寬.

1.當(dāng)重新選擇省的時(shí)候,移除后面的市級(jí)別列表,區(qū)級(jí)別列表
2.移除頂部的市按鈕,區(qū)按鈕.
3.并且底部ScrollView的滾動(dòng)范圍減少至兩屏寬.

1.當(dāng)重新選擇省市的時(shí)候,對(duì)應(yīng)頂部按鈕的寬度跟著改變,對(duì)應(yīng)下級(jí)的按鈕的x值要相應(yīng)調(diào)整
2.按鈕底部的指示條的長(zhǎng)度和位置跟著相應(yīng)變化

其他注意點(diǎn)
1.點(diǎn)擊灰色區(qū)域,取消地址選擇,回到主界面
2.京東用的是網(wǎng)絡(luò)請(qǐng)求獲取省市區(qū)信息,每點(diǎn)擊一個(gè)cell,向服務(wù)器發(fā)送請(qǐng)求,獲取下級(jí)信息.這里用的是本地plist表
下面是plist表的格式

大體思路已經(jīng)出來了,寫代碼中的一些注意點(diǎn)
數(shù)據(jù)源的切換,省市區(qū)各級(jí)別數(shù)據(jù)源,如何處理。在哪里對(duì)數(shù)據(jù)源進(jìn)行賦值
地址模型
#import <Foundation/Foundation.h>
@interface AddressItem : NSObject
//省、市、區(qū) 地名
@property (nonatomic,copy) NSString * name;
//記錄選中狀態(tài),根據(jù)這個(gè)值設(shè)置對(duì)應(yīng)cell內(nèi)label的字體顏色以及是否顯示勾選圖片
@property (nonatomic,assign) BOOL isSelected;
+ (instancetype)initWithName:(NSString *)name isSelected:(BOOL)isSelected;
@end
省級(jí)別數(shù)據(jù)源,直接從plist表中獲取
//省級(jí)別數(shù)據(jù)源
- (NSArray *)dataSouce{
if (_dataSouce == nil) {
//省級(jí)別數(shù)據(jù)源,直接從plist表里面獲取
NSString * path = [[NSBundle mainBundle] pathForResource:@"address.plist" ofType:nil];
NSDictionary * dict = [NSDictionary dictionaryWithContentsOfFile:path];
NSMutableArray * mArray = [NSMutableArray array];
for (NSDictionary * dict0 in dict[@"address"]) {
NSMutableDictionary *mDict = [NSMutableDictionary dictionary];
[mDict setValue:dict0[@"sub"] forKey:@"sub"];
AddressItem * item = [AddressItem initWithName:dict0[@"name"] isSelected:NO];
[mDict setValue:item forKey:@"addressItem"];
[mArray addObject:mDict];
}
_dataSouce = mArray;
}
return _dataSouce;
}
市,地區(qū)級(jí)別數(shù)據(jù)源的賦值。在cell將要選中的代理方法中對(duì)下一級(jí)數(shù)據(jù)源進(jìn)行處理。
//在將要選中cell的代理方法中,對(duì)下一級(jí)數(shù)據(jù)源進(jìn)行處理,要注意的是,這里需要判斷是第一次選中還是切換選中。
- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath{
if([self.tableViews indexOfObject:tableView] == 0){
NSIndexPath * indexPath0 = [tableView indexPathForSelectedRow];
//第二級(jí)數(shù)據(jù)源
_dataSouce1 = [self addressDictToDataSouce:self.dataSouce[indexPath.row][@"sub"]];
if (_dataSouce1.count == 1) { //此時(shí)為直轄市,第二級(jí)的地名都是區(qū)級(jí)別
NSMutableArray * mArray = [NSMutableArray array];
for (NSString * name in _dataSouce1.firstObject[@"sub"]) {
AddressItem * item = [AddressItem initWithName:name isSelected:NO];
[mArray addObject:item];
}
_dataSouce1 = mArray;
}
//之前有選中省,重新選擇省,切換省.
if (indexPath0 != indexPath && indexPath0) {
for (int i = 0; i < self.tableViews.count; i++) {
[self removeLastItem];
}
[self addTopBarItem];
[self addTableView];
AddressItem * item = self.dataSouce[indexPath.row][@"addressItem"];
[self scrollToNextItem:item.name ];
return indexPath;
}
//之前未選中省,第一次選擇省
[self addTopBarItem];
[self addTableView];
AddressItem * item = self.dataSouce[indexPath.row][@"addressItem"];
[self scrollToNextItem:item.name ];
}else if ([self.tableViews indexOfObject:tableView] == 1){
UITableView * tableView0 = self.tableViews[1];
NSIndexPath * indexPath0 = [tableView0 indexPathForSelectedRow];
//重新選擇市,切換市.
if (indexPath0 != indexPath && indexPath0) {
//如果發(fā)現(xiàn)省級(jí)別字典里sub關(guān)聯(lián)的數(shù)組只有一個(gè)元素,說明是直轄市,這時(shí)2級(jí)界面為區(qū)級(jí)別
if ([self.dataSouce1[indexPath.row] isKindOfClass:[AddressItem class]]){
AddressItem * item = self.dataSouce1[indexPath.row];
[self setUpAddress:item.name];
return indexPath;
}
[self removeLastItem];
[self addTopBarItem];
[self addTableView];
AddressItem * item = self.dataSouce1[indexPath.row][@"addressItem"];
[self scrollToNextItem:item.name];
return indexPath;
}
//之前未選中市,第一次選擇
if ([self.dataSouce1[indexPath.row] isKindOfClass:[AddressItem class]]){//只有兩級(jí),此時(shí)self.dataSouce1裝的是直轄市下面區(qū)的數(shù)組
AddressItem * item = self.dataSouce1[indexPath.row];
[self setUpAddress:item.name];
}else{
NSMutableArray * mArray = [NSMutableArray array];
NSArray * tempArray = _dataSouce1[indexPath.row][@"sub"];
for (NSString * name in tempArray) {
AddressItem * item = [AddressItem initWithName:name isSelected:NO];
[mArray addObject:item];
}
_dataSouce2 = mArray;
[self addTopBarItem];
[self addTableView];
AddressItem * item = self.dataSouce1[indexPath.row][@"addressItem"];
[self scrollToNextItem:item.name];
}
}else if ([self.tableViews indexOfObject:tableView] == 2){
AddressItem * item = self.dataSouce2[indexPath.row];
[self setUpAddress:item.name];
}
return indexPath;
}
在cell選中的代理方法中對(duì)數(shù)據(jù)源進(jìn)行修改??刂芻ell的展示
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
AddressTableViewCell * cell = [tableView cellForRowAtIndexPath:indexPath];
AddressItem * item = cell.item;
item.isSelected = YES;
cell.item = item;
}
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath{
AddressTableViewCell * cell = [tableView cellForRowAtIndexPath:indexPath];
AddressItem * item = cell.item;
item.isSelected = NO;
cell.item = item;
}
【當(dāng)重新選擇省市的時(shí)候,對(duì)應(yīng)頂部按鈕的寬度跟著改變,對(duì)應(yīng)下級(jí)的按鈕的x值要相應(yīng)調(diào)整】的處理方案
這里我自定義一個(gè)專門的視圖來存放地址按鈕,每一次對(duì)按鈕title重新賦值,或者有增刪按鈕時(shí),外界只需要調(diào)用視圖的layoutIfNeed方法,這時(shí)會(huì)調(diào)用視圖的layoutSubViews方法進(jìn)行重新布局,按鈕的位置就能很方便的設(shè)置好了。
這樣做的的好處是,外界不需要關(guān)心內(nèi)部如何實(shí)現(xiàn),邏輯會(huì)相對(duì)清晰點(diǎn)。
#import "AddressView.h"
#import "UIView+Frame.h"
static CGFloat const HYBarItemMargin = 20;
@interface AddressView ()
@property (nonatomic,strong) NSMutableArray * btnArray;
@end
@implementation AddressView
- (void)layoutSubviews{
[super layoutSubviews];
for (NSInteger i = 0; i <= self.btnArray.count - 1 ; i++) {
UIView * view = self.btnArray[i];
if (i == 0) {
view.left = HYBarItemMargin;
}
if (i > 0) {
UIView * preView = self.btnArray[i - 1];
view.left = HYBarItemMargin + preView.right;
}
}
}
- (NSMutableArray *)btnArray{
NSMutableArray * mArray = [NSMutableArray array];
for (UIView * view in self.subviews) {
if ([view isKindOfClass:[UIButton class]]) {
[mArray addObject:view];
}
}
_btnArray = mArray;
return _btnArray;
}
@end
源碼地址:https://github.com/HelloYeah/ChooseLocation
歡迎大家checkout,Star...