UIScrollView嵌套滾動完美解決方案:仿淘寶、轉轉首頁

前言

隨着APP承載的業務愈來愈多,一個頁面顯示的信息也愈來愈多,須要爲不一樣的業務導流。主流的平臺APP,諸如:淘寶、京東、轉轉、盒馬、還有各種社交APP的我的主頁,都須要在頁面頂部展現核心業務數據,在底部分標籤顯示各個子業務列表數據。隨着大屏手機的普及,若是隻能經過點擊頂部標籤切換列表,對於使用場景最高的單手操做就很麻煩了。因此,爲了用戶更好的交互,須要支持子列表左右滾動切換的功能。這樣就出現了UIScrollView嵌套滾動的場景了。既須要主列表上下滾動,也須要子列表左右滾動。git

現有的解決方案

爲了解決嵌套滾動的問題,如今網上已經有許多解決方案了。包括筆者我,也開源了一個JXPagingView庫,目前已經有1100 stars,獲得許多朋友的承認。 主要支持如下特性:github

  • 列表懶加載
  • 主列表、子列表下拉刷新
  • 懸浮位置調整
  • OC與Swift雙版本
  • 封裝度高,使用方便

感興趣的能夠了解一下JXPagingView的原理bash

基於現有的原理,有一個小問題:當用戶在頂部header用力往上滑動的時候,當分類控制器滾動到頂部的時候,會忽然停住,列表不會接着慣性繼續滾動。你們能夠打開【京東】APP,目前(版本號:8.3.4)首頁的效果就是如此,你們能夠體驗一下,就明白我說的是什麼意思了。spa

如何才能像淘寶首頁那樣,可讓子列表接着滾動呢?直到看到了轉轉首頁,經過上手體驗以後,發現了一個全新的方案。PS:不知道轉轉APP作了什麼操做,簡單的逆向不起做用,視圖層級都看不到。因此,這個方案都是靠本身猜想加實踐折騰出來的。代理

JXPagerSmoothView方案

JXPagerSmoothView Github地址,點擊立馬體驗code

效果預覽

能夠清楚的看到頂部pagerHeader用力往上滾動以後,下方列表會繼續滾動的,並且滾動的速度、阻尼都是系統自帶的。由於上下滾動的時候,就只是在操做一個列表,天然不會有手勢衝突之類的問題,看了下面的原理解析就明白了。自定義的pagerHeader只是用一個簡單的TableView做爲示例,你能夠用任何複雜的視圖、UICollectionView等代替。cdn

此方案原理很是簡單,沒有複雜的手勢處理,只須要處理好各類邊界狀況便可。blog

狀況一

默認狀況pagerHeaderContainerView被addSubview到當前的列表UIScrollView上面,pagerHeaderContainerView就是頂部pagerheader(核心業務視圖區域)和pinHeader(懸浮分類控制器區域)的容器視圖。這樣子,列表上下滑動就只是在操做單個列表ScrollView,不會有滾動忽然被中斷的狀況。視圖層級以下:get

狀況二

當列表在左右切換的時候、列表向上滾動到pinHeder懸浮的時候,pagerHeaderContainerView被addSubview到JXPagerSmoothView上面,也就是脫離了列表scrollView,達到固定在頂部的效果。視圖層級以下:string

總結:就是在不斷切換pagerHeaderContainerView的父視圖,達到淘寶、轉轉首頁的效果。是否是原理很簡單?固然使用的代碼也很簡單!

使用示例

一、初始化JXPagerSmoothView

self.pager = [[JXPagerSmoothView alloc] initWithDataSource:self];
    [self.view addSubview:self.pager];
複製代碼

二、初始化pagerHeaderpinHeader

self.categoryView = [[JXCategoryTitleView alloc] init];
    self.categoryView.titles = @[@"能力", @"愛好", @"隊友"];
    self.categoryView.contentScrollViewClickTransitionAnimationEnabled = NO;

    self.pagerHeader = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"lufei.jpg"]];
複製代碼

三、實現JXPagerSmoothViewDataSource代理方法

- (CGFloat)heightForPagerHeaderInPagerView:(JXPagerSmoothView *)pagerView {
    return 300;
}

- (UIView *)viewForPagerHeaderInPagerView:(JXPagerSmoothView *)pagerView {
    return self.pagerHeader;
}

- (CGFloat)heightForPinHeaderInPagerView:(JXPagerSmoothView *)pagerView {
    return 50;
}

- (UIView *)viewForPinHeaderInPagerView:(JXPagerSmoothView *)pagerView {
    return self.categoryView;
}

- (NSInteger)numberOfListsInPagerView:(JXPagerSmoothView *)pagerView {
    return self.categoryView.titles.count;
}

- (id<JXPagerSmoothViewListViewDelegate>)pagerView:(JXPagerSmoothView *)pagerView initListAtIndex:(NSInteger)index {
    SmoothListViewController *listVC = [[SmoothListViewController alloc] init];
    return listVC;
}
複製代碼

四、列表實現JXPagerSmoothViewListViewDelegate代理方法

SmoothListViewController類實現JXPagerSmoothViewListViewDelegate代理方法

- (UIScrollView *)listScrollView {
    return self.tableView;
}

- (UIView *)listView {
    return self.view;
}
複製代碼

使用注意事項

經過示例代碼能夠看到整個邏輯簡單、清晰,和使用UITableView同樣,只須要實現對應的代理方法便可,根本不須要操心頁面的交互邏輯。真正的作到了高內聚低耦合、職責分離等原則。

可是有幾個點須要注意:

  • 不要本身設置列表滾動視圖的contentInset屬性,內部經過設置contentInset來添加pagerHeaderContainerView;
  • 當頂部pagerHeader是一個UIScrollView及其子類時,須要讓contentSize.height=pagerHeader的高度,即不能讓其可以滾動,詳情能夠參考OC示例demo的SmoothCustomPagerHeaderViewController類;
  • 請仔細辨別JXPagerViewJXPagerSmoothView的區別,並選擇適合本身需求的類;
  • JXPagerSmoothView在1.2.1及以上版本纔有,請使用最新版本;
  • Swift版本是JXPagingSmoothView;

JXPagerSmoothView Github地址

JXPagerSmoothView Github地址,點擊立馬體驗

總結

JXPagerSmoothView的實現文件只有300行代碼左右,須要深刻研究的朋友,相信花點功夫就能看懂。這樣子之後業務上面有任何特殊要求時,均可以本身實現。只要掌握了原理,就不怕需求的變化。

有任何建議或疑問,能夠留言、提Issues,我都會第一時間回覆你!

感謝你的閱讀,喜歡就點個贊吧💖

相關文章
相關標籤/搜索