實現外賣選餐時兩級 tableView 聯動效果

效果圖:
這裏寫圖片描述
聯動效果
下面說下具體實現步驟:
首先分解一下,實現這個需求主要是兩點,一是點擊左邊tableView,同時滾動右邊tableView到具體的位置。二是拖動右邊tableView選中左邊tableView對應的某一行。要實現這個需求有一點很重要:左邊的tableView每一行對應的是右邊tableView的每個分區.

實現點擊左邊tableView同時滾動右邊tableView,很簡單,只需要實現tableView的代理方法- (void)tableView:(UITableView )tableView didSelectRowAtIndexPath:(NSIndexPath )indexPath;然後在代理方法裏邊拿到右邊的tableView,實現讓其滾動到第indexPath.row分區,第0行即可,代碼如下:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
    // 如果點擊的是右邊的tableView,不做任何處理
    if (tableView == self.rightTableView) return;
    // 點擊左邊的tableView,設置選中右邊的tableView某一行。左邊的tableView的每一行對應右邊tableView的每個分區
    [self.rightTableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:indexPath.row] animated:YES scrollPosition:UITableViewScrollPositionTop];
}

我們這裏不處理右邊tableView的點擊事件,所以if (tableView == self.rightTableView) return;

接下來我們實現 拖動右邊tableView選中左邊tableView對應的某一行,我們要動態選中左邊的tableView,就需要拿到現在滾動到了那個分區,UITableView有兩個代理方法,- (void)tableView:(UITableView )tableView willDisplayHeaderView:(UIView )view forSection:(NSInteger)section // 一個頭標題即將顯示的時候掉用和- (void)tableView:(UITableView )tableView didEndDisplayingHeaderView:(UIView )view forSection:(NSInteger)section // 一個頭標題即將消失的時候掉用
利用這兩個方法就可以拿到當前所在分區實現這個功能了。

還有個更簡單的方法,叫做indexPathsForVisibleRows,官方文檔解釋是:

The value of this property is an array of NSIndexPath objects each representing a row index and section index that together identify a visible row in the table view. If no rows are visible, the value is nil.

簡單意思就是,它返回一個裝着目前屏幕上可見的cell的indexPath集合。

#pragma mark - UIScrollViewDelegate
-(void)scrollViewDidScroll:(UIScrollView *)scrollView{ // 監聽tableView滑動
    // 如果現在滑動的是左邊的tableView,不做任何處理
    if ((UITableView *)scrollView == self.leftTableView) return;
    // 滾動右邊tableView,設置選中左邊的tableView某一行。indexPathsForVisibleRows屬性返回屏幕上可見的cell的indexPath數組,利用這個屬性就可以找到目前所在的分區
    [self.leftTableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:self.rightTableView.indexPathsForVisibleRows.firstObject.section inSection:0] animated:YES scrollPosition:UITableViewScrollPositionMiddle];
}

稍微解釋一下,首先監聽scrollView的拖動,本demo不處理左邊tableView的滾動,所以if ((UITableView *)scrollView == self.leftTableView) return;
self.rightTableView.indexPathsForVisibleRows.firstObject.section這句是拿到當前屏幕上可見cell的第一行cell所在的分區,然後讓左邊的tableView選中第0分區(它只有一個分區)的這一行就OK了。


補充下:點擊左邊tableView的時候會有陰影效果,其實是這樣的,點擊左邊的tableView,右邊的tableView是從當前位置動畫滾動到相應位置的,既然有滾動,就會調- (void)scrollViewDidScroll:(UIScrollView *)scrollView這個代理方法,說白了就是拖動了右邊tableView,拖動右邊的過程中會陸續選中左邊。那我想大家就明白了。
如果不想要這個效果,有兩個辦法,一個是直接吧- (void)tableView:(UITableView )tableView didSelectRowAtIndexPath:(NSIndexPath )indexPath中的動畫滾動的屬性animated值改成NO

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
    // 如果點擊的是右邊的tableView,不做任何處理
    if (tableView == self.rightTableView) return;
    // 點擊左邊的tableView,設置選中右邊的tableView某一行。左邊的tableView的每一行對應右邊tableView的每個分區
    [self.rightTableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:indexPath.row] animated:NO scrollPosition:UITableViewScrollPositionTop];
}

這樣做右邊的tableView就是無動畫滾動了,也就不會再調scrollViewDidScroll:方法。但是如果還想右邊tableViewyou滾動效果,另一種解決方法是:把- (void)scrollViewDidScroll:(UIScrollView )scrollView方法換成- (void)scrollViewDidEndDecelerating:(UIScrollView )scrollView這個代理方法方法就行了。

這個方法也有一個bug:
這個方法調用與否在於你的手指是否在動畫停止之前離開了屏幕,如果在動畫結束之前手指離開屏幕,此方法調用沒什麼問題。but,如果動畫已經停止,再把手指拿開,這個方法是不會調的。

解決這個bug的關鍵在於,讓手指離開的時候手動調一次這個代理方法,那怎麼才能知道手指什麼時候離開呢?scrollView給我們了另一個代理方法:- (void)scrollViewWillEndDragging:(UIScrollView )scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint )targetContentOffset這個方法在結束拖拽的時候調,正好解決了我們的問題:

- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset{
    // 推拽將要結束的時候手動調一下這個方法
    [self scrollViewDidEndDecelerating:scrollView];
}
發佈了26 篇原創文章 · 獲贊 7 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章