【京東收貨地址】

導(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.gif

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

2.gif

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

tmp5deefbb7.png
其他注意點(diǎn)

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

下面是plist表的格式


tmp4fa6b8b2.png

大體思路已經(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...

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫(kù)、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,667評(píng)論 4 61
  • #怪獸動(dòng)物園#系列 第二天 一只害羞的小鱷魚 臨摹自夏七醬的微博 #怪獸動(dòng)物園#系列 今天是母親節(jié),我的字帖也臨摹...
    小許同學(xué)的讀書筆記閱讀 916評(píng)論 0 0
  • 在上一篇文章中,介紹了A+ES的基本概念及適合解決的一些問題,我們看到分布式最終一致性的解決方案的巧妙。如果您想實(shí)...
    cnhuangliang閱讀 951評(píng)論 0 2
  • 我們要走的路很漫長(zhǎng),漫長(zhǎng)到只要一不小心,我們便可以輕易的迷失方向。那是一個(gè)復(fù)雜的世界,我們需要乘坐不同的交通工具,...
    浣久閱讀 292評(píng)論 0 0

友情鏈接更多精彩內(nèi)容