你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發基礎 >> 帶你實現【京東收貨地址】

帶你實現【京東收貨地址】

編輯:IOS開發基礎

導讀

目前大多數APP的地址選擇是用系統的picker View,也不乏用tableview自定義的.

這裡分享一個高仿京東的地址選擇給大家.

源碼地址:https://github.com/HelloYeah/ChooseLocation

歡迎大家Checkout,Star...


下面是京東收貨地址的一些交互以及代碼思路分析

  • 剛打開選擇地址視圖時,底部ScrollView的滾動范圍只有一屏寬.

  • 點擊某個省時,增加對應的市級列表,底部ScrollView橫向滾動區域增加一屏寬.


1338042-16ffa01913c5ccf6.gif



  • 當重新選擇省的時候,移除後面的市級別列表,區級別列表

  • 移除頂部的市按鈕,區按鈕.

  • 並且底部ScrollView的滾動范圍減少至兩屏寬.


1338042-7bc0307bf43ebf45.gif



  • 當重新選擇省市的時候,對應頂部按鈕的寬度跟著改變,對應下級的按鈕的x值要相應調整

  • 按鈕底部的指示條的長度和位置跟著相應變化


1338042-78137181ccaaad4e.png



其他注意點


  • 點擊灰色區域,取消地址選擇,回到主界面

  • 京東用的是網絡請求獲取省市區信息,每點擊一個cell,向服務器發送請求,獲取下級信息.這裡用的是本地plist表


下面是plist表的格式

1338042-0634bafac585c0db.png


大體思路已經出來了,寫代碼時的一些注意點

數據源的切換,省市區各級別數據源,如何處理。在哪裡對數據源進行賦值


  • 地址模型

#import @interface AddressItem : NSObject

//省、市、區 地名
@property (nonatomic,copy) NSString * name;

//記錄選中狀態,根據這個值設置對應cell內label的字體顏色以及是否顯示勾選圖片
@property (nonatomic,assign) BOOL  isSelected; 

+ (instancetype)initWithName:(NSString *)name isSelected:(BOOL)isSelected;

@end


  • 省級別數據源,直接從plist表中獲取

//省級別數據源
- (NSArray *)dataSouce{
    
    if (_dataSouce == nil) {
       //省級別數據源,直接從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;
}

    

  • 市,地區級別數據源的賦值。在cell將要選中的代理方法中對下一級數據源進行處理。


//在將要選中cell的代理方法中,對下一級數據源進行處理,要注意的是,這裡需要判斷是第一次選中還是切換選中。
- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath{
    
     if([self.tableViews indexOfObject:tableView] == 0){
        
        NSIndexPath * indexPath0 = [tableView indexPathForSelectedRow];
        
        //第二級數據源
        _dataSouce1 = [self addressDictToDataSouce:self.dataSouce[indexPath.row][@"sub"]];
    
        if (_dataSouce1.count == 1) { //此時為直轄市,第二級的地名都是區級別
            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) {
        
            //如果發現省級別字典裡sub關聯的數組只有一個元素,說明是直轄市,這時2級界面為區級別
            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]]){//只有兩級,此時self.dataSouce1裝的是直轄市下面區的數組
            
            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選中的代理方法中對數據源進行修改。控制cell的展示

- (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;
}


  • <當重新選擇省市的時候,對應頂部按鈕的寬度跟著改變,對應下級的按鈕的x值要相應調整> 的處理方案


            這裡我自定義一個專門的視圖來存放地址按鈕,每一次對按鈕title重新賦值,或者有增刪按鈕時,外界只需要調用視圖的

layoutIfNeed方法,這時會調用視圖的layoutSubViews方法進行重新布局。按鈕的位置就能很方便的設置好了,這樣做的的好處是,外界不需要關心內部如何實現,邏輯會相對清晰點。

#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  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...



  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved