咱們常常使用美團外賣、餓了麼、口碑等外賣軟件點餐,幾乎全部的外賣軟件所展現的商品類別都無一例外,採用雙列表的形式呈現,商品的分類,以及對商品的下單操做。咱們拿美團外賣爲例,截圖以下:git
暫時忽略頭部視圖,只關注下面的商品分組列表。github
在開始以前,咱們首先應該思考其實現的流程和可能遇到的問題!首先映入眼簾的是左側的商品分類列表,以及右側的分區展示的商品列表。因此:佈局
//分區頭視圖將要顯示 - (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佈局、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" : @[@"甜點組合", @"毛肚", @"菌湯"] }, ];
//分區數 - (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]; }
//單元格內容 - (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; }
測試運行工程能夠看到一個簡單的雙列表已經呈如今你的面前,以下圖所示:優化
//分區頭視圖 - (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的繪製完成了,接下來解決聯動的問題吧。動畫
首先定義一個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
項目地址: