外賣App雙列表聯動

雙列表聯動

用過了那麼多的外賣App,總結出一個規律,那就是「全部的外賣App都有雙列表聯動功能」。哈哈哈哈,這是一個玩笑。git

此次我也須要開發具備聯動效果的雙列表。也是首次開發這種類型的UI,記錄下步驟與心得github

1、關鍵思路

  • 懶加載左右2個UITableView
  • 根據須要自定義Cell
  • 2個UITableView加載到界面上的時候注意下部劇就好
  • 由於須要聯動效果,全部左側的UITableView通常是大的分類,右邊的UITableView通常是大分類小的小分類,因此有了這樣的特色
    • 左邊的UITableView是隻有1個section和n個row
    • 右邊的UITableView具備n個section(這裏的section 個數剛好是左邊UITableView的row數量),且每一個section下的row由對應的數據源控制

2、初版代碼

#pragma mark -- UITableViewDelegate
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
    if (tableView == self.leftTablview) {
        return 1;
    }
    return self.datas.count;
}

-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    if (tableView == self.leftTablview) {
        return self.datas.count;
    }
    QuestionCollectionModel *model = self.datas[section];
    NSArray *questions =model.questions;
    return questions.count;
}

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
    if (tableView == self.leftTablview) {
        return LeftCellHeight;
    }
    return RightCellHeight;
}

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    if (tableView == self.leftTablview) {
        PregnancyPeriodCell *cell = [tableView dequeueReusableCellWithIdentifier:PregnancyPeriodCellID forIndexPath:indexPath];
        if (self.collectionType == CollectionType_Wrong || self.collectionType == CollectionType_Miss) {
            QuestionCollectionModel *model = self.datas[indexPath.row];
            cell.week = model.tag;
        }

        return cell;
    }
    QuestionCell *cell = [tableView dequeueReusableCellWithIdentifier:QuestionCellID forIndexPath:indexPath];
    QuestionCollectionModel *model = self.datas[indexPath.section];
    NSArray *questions =model.questions;
    QuestionModel *questionModel = questions[indexPath.row];
    cell.model = questionModel;
    return cell;
}


-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
    if (tableView == self.leftTablview) {
        NSIndexPath *indexpath = [NSIndexPath indexPathForRow:0 inSection:indexPath.row];
        [self.rightTableview scrollToRowAtIndexPath:indexpath atScrollPosition:UITableViewScrollPositionTop animated:YES];
    }
}

-(void)scrollViewDidScroll:(UIScrollView *)scrollView{
    if (scrollView == self.rightTableview) {
        NSIndexPath *indexpath = [self.rightTableview indexPathsForVisibleRows].firstObject;
        NSIndexPath *leftScrollIndexpath = [NSIndexPath indexPathForRow:indexpath.section inSection:0];
        [self.leftTablview selectRowAtIndexPath:leftScrollIndexpath animated:YES scrollPosition:UITableViewScrollPositionMiddle];

    }
}

缺陷:雖然實現了效果,可是有缺陷。點擊左側的UITableView,右側的UITableViewe滾動到相應的位置,這是沒問題的,可是滾動代理

右邊,須要根據右邊indexPath.section將選中左側相應的indexPath。這樣左側選中的時候,又會觸發右邊滾動的事件,總體看上去不是很流暢。code

3、解決方案

觀察了下,發現右側滾動的時候左側會上下選中,因此也就是隻要讓右側滾動的時候,左側的UITableView單方向選中,不要滾動就好,因此因爲UITableView也是UIScrollview,因此在scrollViewDidScroll方法中判斷右側的UITableView是向上仍是向下滾動,以此做爲判斷條件來讓左側的UITableView選中相應的行。事件

且以前是在scrollview代理方法中讓左側的tableview選中,這樣子又會觸發左側tableview的選中事件,從而致使右側的tablview滾動,形成不嚴謹的聯動邏輯開發

改進後的方法:get

  1. 點擊左側的UITableView,在代理方法didSelectRowAtIndexPath中拿到相應的indexPath.row,計算出右側UITableView須要滾動的indexPath的位置。
    [self.rightTableview scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:indexPath.row] atScrollPosition:UITableViewScrollPositionTop animated:YES];
  2. 在willDisplayCell和didEndDisplayingCell代理方法中選中左側UITableView相應的行。
-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath{

    if (tableView == self.rightTableview  && !self.isScrollDown && self.rightTableview.isDragging ) {
        [self.leftTablview selectRowAtIndexPath:[NSIndexPath indexPathForRow:indexPath.section inSection:0] animated:YES scrollPosition:UITableViewScrollPositionTop];
    }
}



-(void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath{
    if (tableView == self.rightTableview && self.isScrollDown && self.rightTableview.isDragging) {
        [self.leftTablview selectRowAtIndexPath:[NSIndexPath indexPathForRow:indexPath.section+1 inSection:0] animated:YES scrollPosition:UITableViewScrollPositionTop];

    }
}


- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(nonnull NSIndexPath *)indexPath
{
    if (self.leftTablview == tableView)
    {
        [self.rightTableview scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:indexPath.row] atScrollPosition:UITableViewScrollPositionTop animated:YES];
    }else{
        NSLog(@"嗡嗡嗡");
    }
}


#pragma mark - UIScrollViewDelegate

- (void)scrollViewDidScroll:(UIScrollView *)scrollView{

    static CGFloat lastOffsetY = 0;

    UITableView *tableView = (UITableView *)scrollView;
    if (self.rightTableview == tableView){
        self.isScrollDown = (lastOffsetY < scrollView.contentOffset.y);
        lastOffsetY = scrollView.contentOffset.y;
    }

}
效果圖

效果圖

附上Demo:Demoit

相關文章
相關標籤/搜索