iOS仿微博發(fā)現(xiàn)頁實(shí)現(xiàn)

某一天接到一個(gè)需求,要求做一個(gè)類似微博發(fā)現(xiàn)頁的頁面,需要支持上下滑動(dòng)的同時(shí)可以左右滑動(dòng)展示更多的內(nèi)容,就像下圖這樣

WX20190617-135231.png

藍(lán)框下方的部分可以左右滑動(dòng),藍(lán)框以及藍(lán)框上邊的部分不可以左右滑,點(diǎn)擊藍(lán)框中的title藍(lán)框下方會(huì)切換不同的頁面,左右滑藍(lán)框下方的頁面藍(lán)框里的title也會(huì)實(shí)時(shí)變化為高亮,往上滑的時(shí)候藍(lán)框內(nèi)的部分會(huì)吸頂

大致的實(shí)現(xiàn)方法是用一個(gè)大的TableView實(shí)現(xiàn),這個(gè)頁面大概可以分為三部分


WX20190617-135136.png
  • 第一部分是固定的,其實(shí)就是tableView的HeadView
  • 第二部分(暫且叫做categoryView) 其實(shí)是tableView的第一個(gè)section的headerView,內(nèi)部有一個(gè)點(diǎn)擊切換的效果
  • 第三部分是tableView的一個(gè)Cell,Cell內(nèi)部是一個(gè)UICollectionView,可以左右滑動(dòng),滑動(dòng)時(shí)與categoryView聯(lián)動(dòng),collectionView的每一個(gè)cell是一個(gè)TableView,在categoryView吸頂?shù)臅r(shí)候可以自由滑動(dòng)

難題一:當(dāng)視圖滑動(dòng)一部分之后,手指在第三部分滑動(dòng)的時(shí)候,會(huì)觸發(fā)第三部分視圖內(nèi)的某個(gè)TableView的滑動(dòng),這時(shí)候外部的大的tableView就會(huì)失去滑動(dòng)效果,想要滑動(dòng)只能是滑動(dòng)第三部分上方的視圖。

解決方案:將最外部的tableView變成新建的一個(gè)tableView類,(繼承自UITableView)然后將它的- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer方法重寫

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
    return [gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]] && [otherGestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]];
}

這樣可以保證你在滑動(dòng)第三部分里的小的tableView時(shí),外部的大的tableView依然可以滑動(dòng),但這時(shí)候這兩種滑動(dòng)會(huì)重疊,也就是說你滑動(dòng)第三部分的tableView時(shí),大的tableView也在滑動(dòng),我們要的效果是無論何時(shí)只有一個(gè)tableView在滑動(dòng),所以我們要實(shí)時(shí)監(jiān)測這兩個(gè)tableView的偏移量,當(dāng)一個(gè)tableView滑動(dòng)的時(shí)候讓另一個(gè)tableView的contentOffset始終為0,造成一種不動(dòng)的錯(cuò)覺,分兩種情況:

  • 第二部分沒有吸頂?shù)臅r(shí)候,保持外部的大tableView滑動(dòng)效果,小tableView雖然也可以滑動(dòng),但是要造成它不動(dòng)的效果
  • 第二部分吸頂?shù)臅r(shí)候,只讓小的tableView滑動(dòng),外部的大tableView要造成不動(dòng)的效果

同時(shí)檢測這兩個(gè)tableView的代理方法- (void)scrollViewDidScroll:(UIScrollView *)scrollView,針對(duì)大的TableView:

    if (self.currentScrollingListView != nil && self.currentScrollingListView.contentOffset.y > 0) {
        //mainTableView的header已經(jīng)滾動(dòng)不見,開始滾動(dòng)某一個(gè)listView,那么固定mainTableView的contentOffset,讓其不動(dòng)
        self.mainTableView.contentOffset = CGPointMake(0, [self.delegate tableHeaderViewHeightInPagerView:self]);
    }

    if (scrollView.contentOffset.y < [self.delegate tableHeaderViewHeightInPagerView:self]) {
        //mainTableView已經(jīng)顯示了header,listView的contentOffset需要重置
        NSArray *listViews = [self.delegate listViewsInPagerView:self];
        for (UIView <JXPagerViewListViewDelegate>* listView in listViews) {
            [listView listScrollView].contentOffset = CGPointZero;
        }
    }

針對(duì)小的tableView

    if (self.mainTableView.contentOffset.y < [self.delegate tableHeaderViewHeightInPagerView:self]) {
        //mainTableView的header還沒有消失,讓listScrollView一直為0
        scrollView.contentOffset = CGPointZero;
        scrollView.showsVerticalScrollIndicator = NO;
    }else {
        //mainTableView的header剛好消失,固定mainTableView的位置,顯示listScrollView的滾動(dòng)條
        self.mainTableView.contentOffset = CGPointMake(0, [self.delegate tableHeaderViewHeightInPagerView:self]);
        scrollView.showsVerticalScrollIndicator = YES;
    }

這樣就可以實(shí)現(xiàn)一種自動(dòng)吸頂同時(shí)又比較順滑的滑動(dòng)效果

難題二: categoryView與第三部分多個(gè)View的聯(lián)動(dòng)效果

categoryView的實(shí)現(xiàn)方式是用一個(gè)collectionView實(shí)現(xiàn)的,下方第三部分也是一個(gè)collectionView, 在封裝第二部分視圖的時(shí)候,里邊有一個(gè)UIScrollview類型的屬性,將第三部分的collectionView賦給這個(gè)屬性,然后通過KVO監(jiān)聽第三部分collectionView的滑動(dòng),就可以將第二部分的collectionView的cell的點(diǎn)擊事件和第三個(gè)collectionView的滑動(dòng)關(guān)聯(lián)起來

[contentScrollView addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew context:nil];
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
{
    if ([keyPath isEqualToString:@"contentOffset"] && (self.contentScrollView.isTracking || self.contentScrollView.isDecelerating)) {
        //用戶滾動(dòng)引起的contentOffset變化,才處理。
        CGPoint contentOffset = [change[NSKeyValueChangeNewKey] CGPointValue];
        [self contentOffsetOfContentScrollViewDidChanged:contentOffset];
    }
}

這里只是記錄了大體的思路,來理解這個(gè)效果是怎樣實(shí)現(xiàn)的,其實(shí)還有很多需要注意的細(xì)節(jié),源代碼是兩個(gè)第三方JXCategoryViewJXPagingView

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對(duì)...
    cosWriter閱讀 11,644評(píng)論 1 32
  • ----“求真悟道”2019全國小學(xué)數(shù)學(xué)教育論壇歸來 2019年6月2日-3日參加了由《教育研究與評(píng)論》和《教育視...
    華琴_5c0e閱讀 1,284評(píng)論 0 0
  • 為了日更,每晚寫到十一二點(diǎn)。 昨晚發(fā)布一篇,看了一下時(shí)間11:48分,自我感覺還拿得出手,于是找了幾個(gè)專題投稿,投...
    清風(fēng)雪1閱讀 1,050評(píng)論 10 7
  • 2018.8.21號(hào)星期二晴三一班麻永卓媽媽 由于下雨的原因,兩天了都沒有來水,這個(gè)時(shí)候才知道水是多么的重...
    a愛英閱讀 258評(píng)論 0 2
  • 雨是一把神秘的鑰匙,開啟了山 我與春天一同步入山中 海在天上,繁星追逐群山 野薔薇是群山卷起的浪花 時(shí)光微微香,因...
    大小周閱讀 975評(píng)論 18 24

友情鏈接更多精彩內(nèi)容