【iOS開發實戰】經典的外賣列表(雙Table聯動)

        咱們常常使用美團外賣、餓了麼、口碑等外賣軟件點餐,幾乎全部的外賣軟件所展現的商品類別都無一例外,採用雙列表的形式呈現,商品的分類,以及對商品的下單操做。咱們拿美團外賣爲例,截圖以下:git

暫時忽略頭部視圖,只關注下面的商品分組列表。github

思路:

        在開始以前,咱們首先應該思考其實現的流程和可能遇到的問題!首先映入眼簾的是左側的商品分類列表,以及右側的分區展示的商品列表。因此:佈局

  • 咱們至少須要兩個tableView,單純的放上兩個tableView還不能知足實際需求。
  • 拿美團外賣這個界面來看,點擊左側商品分類,右側的商品列表會將該分類的分區第一條數據滾動至右側tableView的頂部。用戶滾動右側列表,左側分類列表會隨之高亮顯示相應的分類標籤。能夠經過UITableViewDelegate的協議,即分區頭、腳視圖的顯示週期,以及UIScrollViewDelegate的相應協議來實現左側和右側列表的聯動。並結合tableView的滾動方法實現雙列表的聯動效果。
  • //分區頭視圖將要顯示
    - (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section
    //分區腳視圖已經結束顯示
    - (void)tableView:(UITableView *)tableView didEndDisplayingFooterView:(UIView *)view forSection:(NSInteger)section
    //以及結束減速
    - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate;
    //滾動至某一行
    - (void)scrollToRowAtIndexPath:(NSIndexPath *)indexPath atScrollPosition:(UITableViewScrollPosition)scrollPosition animated:(BOOL)animated;

     

實踐:

一、建立兩個tableView:

  •     爲了儘量簡單實現,咱們採用StoryBoard來建立這兩個tableView(固然你也可使用代碼來建立),左側tableView寬度爲固定寬度100,右側tableView寬度爲剩餘屏幕寬度,這裏採用自動佈局技術約束(這裏再也不贅述其實現過程)。以下圖所示:


兩個tableView佈局、delegate的鏈接 及 關聯代碼測試

二、模擬分類的商品數據

_relate = YES;    
goodsList = @[
                      @{@"title" : @"精選特賣",
                        @"list" : @[@"甜點組合", @"毛肚", @"菌湯", @"甜點組合", @"毛肚", @"菌湯",@"甜點組合", @"毛肚", @"菌湯"]
                        },
                      @{@"title" : @"飯後(含有茶點)",
                        @"list" : @[@"甜點組合", @"毛肚", @"菌湯"]
                        },
                      @{@"title" : @"茶點(含有茶點)",
                        @"list" : @[@"甜點組合", @"毛肚", @"菌湯",@"甜點組合", @"毛肚", @"菌湯"]
                        },
                      @{@"title" : @"素材水果拼盤",
                        @"list" : @[@"甜點組合", @"毛肚", @"菌湯",@"甜點組合", @"毛肚", @"菌湯",@"甜點組合", @"毛肚", @"菌湯",@"甜點組合", @"毛肚", @"菌湯",]
                        },
                      @{@"title" : @"水果拼盤生鮮果",
                        @"list" : @[@"甜點組合", @"毛肚", @"菌湯",]
                        },
                      @{@"title" : @"拼盤",
                        @"list" : @[@"甜點組合"]
                        },
                      @{@"title" : @"烤魚盤",
                        @"list" : @[@"甜點組合", @"毛肚", @"菌湯",@"甜點組合", @"毛肚", @"菌湯"]
                        },
                      @{@"title" : @"飲料",
                        @"list": @[@"甜點組合", @"毛肚", @"菌湯",@"甜點組合", @"毛肚", @"菌湯",@"甜點組合", @"毛肚", @"菌湯",@"甜點組合", @"毛肚", @"菌湯"]
                        },
                      @{@"title": @"小吃",
                        @"list": @[@"甜點組合", @"毛肚"]
                        },
                      @{@"title" : @"做料",
                        @"list" : @[@"甜點組合", @"毛肚", @"菌湯"]
                        },
                      @{@"title" : @"主食",
                        @"list" : @[@"甜點組合", @"毛肚", @"菌湯"]
                        },
                      ];


三、繪製兩tableView

  •     首先別忘了讓ViewController遵照tableView的delegate:

  • 分區數、行數的實現:
//分區數
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
    if (tableView==_leftTableView) {
        return 1;
    }
    return goodsList.count;
}

//行數
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    if (tableView==_leftTableView) {
        return goodsList.count;
    }
    return [[goodsList[section] objectForKey:@"list"] count];
}
  • 單元格內容的實現,這裏只使用系統簡單的cell風格,左側cell高度默認80,右側默認100,以下圖所示:
//單元格內容
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
    if (cell==nil) {
        cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cell"];
    }
    if (tableView==_leftTableView) {
        //分類標題
        cell.textLabel.text = [goodsList[indexPath.row] objectForKey:@"title"];
    }else{
        //商品標題
        cell.textLabel.text = [[goodsList[indexPath.section] objectForKey:@"list"] objectAtIndex:indexPath.row];
    }
    return cell;
}

//行高
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
    if (tableView==_leftTableView) {
        return 80;
    }
    return 100;
}

    測試運行工程能夠看到一個簡單的雙列表已經呈如今你的面前,以下圖所示:優化

  • 繪製分區頭視圖,高度設置爲30:
//分區頭視圖
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{
    if (tableView==_rightTableView) {
        UIView * view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, _rightTableView.bounds.size.width, 30)];
        view.backgroundColor = [UIColor colorWithWhite:0.9 alpha:0.9];
        UILabel * label = [[UILabel alloc] initWithFrame:view.bounds];
        [view addSubview:label];
        label.text = [goodsList[section] objectForKey:@"title"];
        return view;
    }
    return nil;
}

//分區頭視圖高度
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{
    if (tableView==_leftTableView) {
        return CGFLOAT_MIN;
    }
    return 30;
}

//腳視圖高度
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section{
    if (tableView == self.leftTableView) {
        return 0;
    } else {
        //重要
        return CGFLOAT_MIN;
    }
}

       

    至此,兩個tableView的繪製完成了,接下來解決聯動的問題吧。動畫

四、兩個tableView的聯動

    首先定義一個BOOL類型的變量_relate 來標記左側列表是否滾動,在viewDidLoad和下面的代理中把_relate置爲YES:spa

#pragma mark - UIScrollViewDelegate
//已經結束減速
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
    _relate = YES;
}
  • 實現點擊左側單元格,右側列表自動滾動到相應分區
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    if (tableView == _leftTableView) {
        _relate = NO;
        //選擇該行,並自動滾動至列表中心區域
        [self.leftTableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionMiddle];
        //右側滾動至相應分區
        [self.rightTableView scrollToRowAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:indexPath.row] atScrollPosition:UITableViewScrollPositionTop animated:YES];
    }else {
        //取消選中
        [self.rightTableView deselectRowAtIndexPath:indexPath animated:NO];
        
    }
}

 

  • 實現滾動右側列表,左側列表自動選中相應分區標題
//分區頭即將顯示
- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section {
    if (_relate) {
        //獲取顯示在最頂部的cell的分區數
        NSInteger topCellSection = [[[tableView indexPathsForVisibleRows] firstObject] section];
        if (tableView == self.rightTableView) {
            //滾動該分區對應的標題至列表靠近中部區域
            [self.leftTableView selectRowAtIndexPath:[NSIndexPath indexPathForItem:topCellSection inSection:0] animated:YES scrollPosition:UITableViewScrollPositionMiddle];
        }
    }
}

//分區頭已經結束顯示
- (void)tableView:(UITableView *)tableView didEndDisplayingFooterView:(UIView *)view forSection:(NSInteger)section {
    if (_relate) {
        //獲取顯示在最頂部的cell的分區數
        NSInteger topCellSection = [[[tableView indexPathsForVisibleRows] firstObject] section];
        if (tableView == self.rightTableView) {
            //滾動該分區對應的標題至列表靠近中部區域
            [self.leftTableView selectRowAtIndexPath:[NSIndexPath indexPathForItem:topCellSection inSection:0] animated:YES scrollPosition:UITableViewScrollPositionMiddle];
        }
    }
}

至此一個簡單實用的經典雙列表聯動效果已經實現了!代理

Demo地址:code

https://github.com/ly918/Demosget

 

優化:


另外,我對其作了進一步的擴展優化,如加入購物車的動畫,導航漸變等,效果圖以下所示:

項目地址:

https://github.com/ly918/TakeawayList-ShoppingCart

相關文章
相關標籤/搜索