UIScrollView嵌套滚动完美解决方案:仿淘宝、转转首页

前言

随着APP承载的业务越来越多,一个页面显示的信息也越来越多,需要为不同的业务导流。主流的平台APP,诸如:淘宝、京东、转转、盒马、还有各类社交APP的个人主页,都需要在页面顶部展示核心业务数据,在底部分标签显示各个子业务列表数据。随着大屏手机的普及,如果只能通过点击顶部标签切换列表,对于使用场景最高的单手操作就很麻烦了。所以,为了用户更好的交互,需要支持子列表左右滚动切换的功能。这样就出现了UIScrollView嵌套滚动的场景了。既需要主列表上下滚动,也需要子列表左右滚动。

现有的解决方案

为了解决嵌套滚动的问题,现在网上已经有许多解决方案了。包括笔者我,也开源了一个JXPagingView库,目前已经有1100 stars,得到许多朋友的认可。
主要支持以下特性:

  • 列表懒加载
  • 主列表、子列表下拉刷新
  • 悬浮位置调整
  • OC与Swift双版本
  • 封装度高,使用方便

感兴趣的可以了解一下JXPagingView的原理

基于现有的原理,有一个小问题:当用户在顶部header用力往上滑动的时候,当分类控制器滚动到顶部的时候,会突然停住,列表不会接着惯性继续滚动。大家可以打开【京东】APP,目前(版本号:8.3.4)首页的效果就是如此,大家可以体验一下,就明白我说的是什么意思了。

如何才能像淘宝首页那样,可以让子列表接着滚动呢?直到看到了转转首页,通过上手体验之后,发现了一个全新的方案。PS:不知道转转APP做了什么操作,简单的逆向不起作用,视图层级都看不到。所以,这个方案都是靠自己猜测加实践折腾出来的。

JXPagerSmoothView方案

JXPagerSmoothView Github地址,点击立马体验

效果预览

image

可以清楚的看到顶部pagerHeader用力往上滚动之后,下方列表会继续滚动的,而且滚动的速度、阻尼都是系统自带的。因为上下滚动的时候,就只是在操作一个列表,自然不会有手势冲突之类的问题,看了下面的原理解析就明白了。自定义的pagerHeader只是用一个简单的TableView作为示例,你可以用任何复杂的视图、UICollectionView等代替。

此方案原理非常简单,没有复杂的手势处理,只需要处理好各种边界情况即可。

情况一

默认情况pagerHeaderContainerView被addSubview到当前的列表UIScrollView上面,pagerHeaderContainerView就是顶部pagerheader(核心业务视图区域)和pinHeader(悬浮分类控制器区域)的容器视图。这样子,列表上下滑动就只是在操作单个列表ScrollView,不会有滚动突然被中断的情况。视图层级如下:

image

情况二

当列表在左右切换的时候、列表向上滚动到pinHeder悬浮的时候,pagerHeaderContainerView被addSubview到JXPagerSmoothView上面,也就是脱离了列表scrollView,达到固定在顶部的效果。视图层级如下:

image

总结:就是在不断切换pagerHeaderContainerView的父视图,达到淘宝、转转首页的效果。是不是原理很简单?当然使用的代码也很简单!

使用示例

1、初始化JXPagerSmoothView

    self.pager = [[JXPagerSmoothView alloc] initWithDataSource:self];
    [self.view addSubview:self.pager];

2、初始化pagerHeaderpinHeader

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

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

3、实现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;
}

4、列表实现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,我都会第一时间回复你!

感谢你的阅读,喜欢就点个赞吧💖

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容

  • 简书编辑器目测不支持html的一些语法,导致部分图片显示有问题,对于图片又最大只支持5M,建议前往原文地址或者是掘...
    Jiar_阅读 3,850评论 2 2
  • 你是谁 你在寻找谁 你在扮演谁 你在逃避谁 你独自一人躲进了寒夜 所有的火焰被撕成白雪 你无力地掬着雪花 想点燃它...
    季梦VC_ETG阅读 268评论 0 4
  • 社交是一个广义的概念,就互联网产品开发而言,社交app的开发思路已经明显从社交通讯功能,转向社交表达功能。一方面,...
    冬瓜西瓜阅读 284评论 0 0
  • 每个人的人生,都是一场独特的旅行,前方未知,也许藏着精彩无限,这一生,你遇见谁错过谁,都不重要,重要的是,你是否能...
    安心悦舍阅读 324评论 3 2
  • HTML5定义了一些新的标记规则,也定义了一些新的JavaScript API,能够让开发人员创建出更好的用户界面...
    jluemmmm阅读 195评论 0 0