{"id":15029224,"url":"https://github.com/pujiaxin33/jxpagingview","last_synced_at":"2025-05-13T20:08:16.308Z","repository":{"id":37743345,"uuid":"144228588","full_name":"pujiaxin33/JXPagingView","owner":"pujiaxin33","description":"类似微博主页、简书主页等效果。多页面嵌套，既可以上下滑动，也可以左右滑动切换页面。支持HeaderView悬浮、支持下拉刷新、上拉加载更多。","archived":false,"fork":false,"pushed_at":"2025-03-14T06:10:16.000Z","size":10232,"stargazers_count":2975,"open_issues_count":47,"forks_count":573,"subscribers_count":37,"default_branch":"master","last_synced_at":"2025-04-09T03:05:09.159Z","etag":null,"topics":["page","pageview","pagingview","scrollview","segmentedcontrol"],"latest_commit_sha":null,"homepage":"","language":"Objective-C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pujiaxin33.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-08-10T02:50:31.000Z","updated_at":"2025-04-08T08:19:44.000Z","dependencies_parsed_at":"2024-06-18T12:25:52.453Z","dependency_job_id":"3c9c8e61-2953-4510-83fb-a71b8653273e","html_url":"https://github.com/pujiaxin33/JXPagingView","commit_stats":{"total_commits":390,"total_committers":9,"mean_commits":"43.333333333333336","dds":"0.22564102564102562","last_synced_commit":"a55dd07adfa9729677e2287943af5aa40f5df31f"},"previous_names":[],"tags_count":70,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pujiaxin33%2FJXPagingView","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pujiaxin33%2FJXPagingView/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pujiaxin33%2FJXPagingView/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pujiaxin33%2FJXPagingView/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pujiaxin33","download_url":"https://codeload.github.com/pujiaxin33/JXPagingView/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251297308,"owners_count":21566796,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["page","pageview","pagingview","scrollview","segmentedcontrol"],"created_at":"2024-09-24T20:09:59.903Z","updated_at":"2025-04-28T10:42:32.522Z","avatar_url":"https://github.com/pujiaxin33.png","language":"Objective-C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# JXPagingView\n\n类似微博主页、简书主页、QQ联系人页面等效果。多页面嵌套，既可以上下滑动，也可以左右滑动切换页面。支持HeaderView悬浮、支持下拉刷新、上拉加载更多。\n\n## 功能特点\n\n- 支持OC与Swift;\n- 支持列表懒加载，等到列表真正显示的时候才加载，而不是一次性加载所有列表；\n- 支持首页下拉刷新、列表视图下拉刷新、列表视图上拉加载更多；\n- 支持悬浮SectionHeader的垂直位置调整；\n- 支持从顶部用力往上滚动，下面的列表会跟着滚动，而不会突然卡主，需要使用`JXPagerSmoothView`类；\n- 列表封装简洁，只要遵从`JXPagingViewListViewDelegate`协议即可。UIView、UIViewController等都可以；\n- 使用JXCategoryView/JXSegmentedView分类控制器，几乎支持所有主流效果、高度自定义、可灵活扩展；\n- 支持横竖屏切换；\n- 支持点击状态栏滚动当前列表到顶部；\n- 支持列表显示和消失的生命周期方法；\n- isListHorizontalScrollEnabled属性控制列表是否可以左右滑动，默认YES；\n- 支持`FDFullscreenPopGesture`等全屏手势兼容处理；\n\n## 预览\n\n| 效果  | 预览图 |\n|-------|-------|\n| **头图缩放** \u003cbr/\u003e参考[ZoomViewController](https://github.com/pujiaxin33/JXPagingView/tree/master/Examples/JXPagerViewExample-OC/JXPagerViewExample-OC/Example/Zoom/ZoomViewController.m)类 | ![Zoom](https://github.com/pujiaxin33/JXExampleImages/blob/master/JXPaingView/Zoom.gif) | \n| **主页下拉刷新\u0026列表上拉加载更多** \u003cbr/\u003e参考[RefreshViewController](https://github.com/pujiaxin33/JXPagingView/tree/master/Examples/JXPagerViewExample-OC/JXPagerViewExample-OC/Example/Refresh/RefreshViewController.m)类 | ![Refresh](https://github.com/pujiaxin33/JXExampleImages/blob/master/JXPaingView/Refresh.gif) |\n| **列表下拉刷新** \u003cbr/\u003e参考[ListRefreshViewController](https://github.com/pujiaxin33/JXPagingView/tree/master/Examples/JXPagerViewExample-OC/JXPagerViewExample-OC/Example/Refresh/ListRefreshViewController.m)类 | ![Refresh](https://github.com/pujiaxin33/JXExampleImages/blob/master/JXPaingView/ListRefresh.gif) |\n| **悬浮sectionHeader位置调整**  | ![Refresh](https://github.com/pujiaxin33/JXExampleImages/blob/master/JXPaingView/PinSectionHeaderPosition.gif) |\n| **导航栏隐藏** \u003cbr/\u003e 参考[NaviBarHiddenViewController](https://github.com/pujiaxin33/JXPagingView/tree/master/Examples/JXPagerViewExample-OC/JXPagerViewExample-OC/Example/NavigationBarHidden/NaviBarHiddenViewController.m)类 | ![Refresh](https://github.com/pujiaxin33/JXExampleImages/blob/master/JXPaingView/NaviHidden.gif) |\n| **CollectionView列表示例**\u003cbr/\u003e参考[CollectionViewViewController.swift](https://github.com/pujiaxin33/JXPagingView/tree/master/Examples/JXPagingViewExample/JXPagingViewExample/Example/CollectionView/CollectionViewViewController.swift)类 \u003cbr/\u003e 只有swift的demo工程有该示例 | ![Refresh](https://github.com/pujiaxin33/JXExampleImages/blob/master/JXPaingView/CollectionViewList.gif) |\n| **HeaderView更新高度示例**\u003cbr/\u003e 参考[HeightChangeAnimationViewController.swift](https://github.com/pujiaxin33/JXPagingView/tree/master/Examples/JXPagingViewExample/JXPagingViewExample/Example/HeightChange/HeightChangeAnimationViewController.swift)类 \u003cbr/\u003e 只有swift demo工程才有该示例 | ![Refresh](https://github.com/pujiaxin33/JXExampleImages/blob/master/JXPaingView/HeaderViewHeightChange.gif) |\n| **PagingView嵌套CategoryView** \u003cbr/\u003e 参考[NestViewController](https://github.com/pujiaxin33/JXPagingView/tree/master/Examples/JXPagerViewExample-OC/JXPagerViewExample-OC/Example/Nest/NestViewController.m)类 \u003cbr/\u003e 只有 **OC!OC!OC!** 的demo工程才有该示例 \u003cbr/\u003e 操作比较特殊，如果需要此效果，\u003cbr/\u003e 请认真参考源码，有问题多试试 \u003cbr/\u003e 参考NestViewController.h类 | ![Nest](https://github.com/pujiaxin33/JXExampleImages/blob/master/JXPaingView/Nest.gif) |\n| **CategoryView嵌套PagingView** \u003cbr/\u003e 参考[NestViewController.swift](https://github.com/pujiaxin33/JXPagingView/tree/master/Examples/JXPagingViewExample/JXPagingViewExample/Example/CategoryNestPaging/NestViewController.swift)类 \u003cbr/\u003e 只有 **Swift!Swift!Swift!** 的demo工程才有该示例 \u003cbr/\u003e 操作比较特殊，如果需要此效果，\u003cbr/\u003e 请认真参考源码，有问题多试试 \u003cbr/\u003e 参考NestViewController.swift类 | ![Nest](https://github.com/pujiaxin33/JXExampleImages/blob/master/JXPaingView/CategoryNestPaging.gif) |\n| **PagingView嵌套PagingView** \u003cbr/\u003e 参考[NestViewController.swift](https://github.com/pujiaxin33/JXPagingView/blob/master/Examples/JXPagingViewExample/JXPagingViewExample/Example/PagingNestPaging/PagingNestPagingExampleViewController.swift)类 \u003cbr/\u003e 只有 **Swift!Swift!Swift!** 的demo工程才有该示例 \u003cbr/\u003e 操作比较特殊，如果需要此效果，\u003cbr/\u003e 请认真参考源码，有问题多试试 \u003cbr/\u003e 参考PagingNestPagingExampleViewController.swift类 | ![PagingView嵌套PagingView](https://github.com/pujiaxin33/JXExampleImages/blob/master/JXPaingView/pagingNestPaging.gif) |\n| **点击状态栏**  | ![Zoom](https://github.com/pujiaxin33/JXExampleImages/blob/master/JXPaingView/StatusBarClicked.gif) | \n| **横竖屏旋转**  | ![Zoom](https://github.com/pujiaxin33/JXExampleImages/blob/master/JXPaingView/ScreenRotate.gif) | \n| **JXPageListView**\u003cbr/\u003e 顶部需要自定义cell的场景，类似于电商APP首页，滑动到列表最底部才是分类控制器 \u003cbr/\u003e 该效果是另一个库，点击查看[JXPageListView](https://github.com/pujiaxin33/JXPageListView) \u003cbr/\u003e 该效果是另一个库，点击查看[JXPageListView](https://github.com/pujiaxin33/JXPageListView) \u003cbr/\u003e 该效果是另一个库，点击查看[JXPageListView](https://github.com/pujiaxin33/JXPageListView) | ![list](https://github.com/pujiaxin33/JXPageListView/blob/master/JXPageListView/Gif/headerLoading.gif) |\n| **JXPagerSmoothView**\u003cbr/\u003e 类似淘宝、转转首页 \u003cbr/\u003e 从顶部用力往上滚动，下面的列表会继续滚动  |  ![smooth](https://github.com/pujiaxin33/JXExampleImages/blob/master/JXPaingView/smooth.gif)  |\n\n## 安装\n\n### 手动\n\n**Swift版本：** Clone代码，拖入JXPagingView-Swift文件夹，使用`JXPagingView`类；\n\n**OC版本：** Clone代码，拖入JXPagerView文件夹，使用`JXPagerView`类；\n\n### CocoaPods\n\n- **Swift版本**\n\n支持swift版本：5.0+\n\n```ruby\ntarget '\u003cYour Target Name\u003e' do\n    pod 'JXPagingView/Paging'\nend\n```\n\n- **OC版本**\n```ruby\ntarget '\u003cYour Target Name\u003e' do\n    pod 'JXPagingView/Pager'\nend\n```\n\nSwift与OC的仓库地址不一样，请注意选择！\n\n先`pod repo update`然后再`pod install`\n\n\n## 使用\n\nswift版本使用类似，只是类名及相关API更改为`JXPagingView`，具体细节请查看Swfit工程。\n\n### 1、初始化`JXCategoryTitleView`和`JXPagerView`\n\n```Objective-C\nself.categoryView = [[JXCategoryTitleView alloc] initWithFrame:frame];\n//配置categoryView，细节参考源码\n\nself.pagerView = [[JXPagerView alloc] initWithDelegate:self];\n[self.view addSubview:self.pagerView];\n\n//⚠️⚠️⚠️将pagerView的listContainerView和categoryView.listContainer进行关联，这样列表就可以和categoryView联动了。⚠️⚠️⚠️\nself.categoryView.listContainer = (id\u003cJXCategoryViewListContainer\u003e)self.pagerView.listContainerView;\n```\n\n**Swift版本列表关联代码**\n```Swift\n//给JXPagingListContainerView添加extension，表示遵从JXSegmentedViewListContainer的协议\nextension JXPagingListContainerView: JXSegmentedViewListContainer {}\n//⚠️⚠️⚠️将pagingView的listContainerView和segmentedView.listContainer进行关联，这样列表就可以和categoryView联动了。⚠️⚠️⚠️\nsegmentedView.listContainer = pagingView.listContainerView\n```\n\n### 2、实现`JXPagerViewDelegate`协议\n\n```Objective-C\n/**\n 返回tableHeaderView的高度，因为内部需要比对判断，只能是整型数\n */\n- (NSUInteger)tableHeaderViewHeightInPagerView:(JXPagerView *)pagerView {\n    return JXTableHeaderViewHeight;\n}\n\n/**\n 返回tableHeaderView\n */\n- (UIView *)tableHeaderViewInPagerView:(JXPagerView *)pagerView {\n    return self.userHeaderView;\n}\n\n\n/**\n 返回悬浮HeaderView的高度，因为内部需要比对判断，只能是整型数\n */\n- (NSUInteger)heightForPinSectionHeaderInPagerView:(JXPagerView *)pagerView {\n    return JXheightForHeaderInSection;\n}\n\n\n/**\n 返回悬浮HeaderView\n */\n- (UIView *)viewForPinSectionHeaderInPagerView:(JXPagerView *)pagerView {\n    return self.categoryView;\n}\n\n/**\n 返回列表的数量\n */\n- (NSInteger)numberOfListsInPagerView:(JXPagerView *)pagerView {\n    //和categoryView的item数量一致\n    return self.titles.count;\n}\n\n/**\n 根据index初始化一个对应列表实例。注意：一定要是新生成的实例！！！\n 只要遵循JXPagerViewListViewDelegate即可，无论你返回的是UIView还是UIViewController都可以。\n */\n- (id\u003cJXPagerViewListViewDelegate\u003e)pagerView:(JXPagerView *)pagerView initListAtIndex:(NSInteger)index {\n    TestListBaseView *listView = [[TestListBaseView alloc] init];\n    if (index == 0) {\n        listView.dataSource = @[@\"橡胶火箭\", @\"橡胶火箭炮\", @\"橡胶机关枪\"...].mutableCopy;\n    }else if (index == 1) {\n        listView.dataSource = @[@\"吃烤肉\", @\"吃鸡腿肉\", @\"吃牛肉\", @\"各种肉\"].mutableCopy;\n    }else {\n        listView.dataSource = @[@\"【剑士】罗罗诺亚·索隆\", @\"【航海士】娜美\", @\"【狙击手】乌索普\"...].mutableCopy;\n    }\n    [listView beginFirstRefresh];\n    return listView;\n}\n```\n\n### 3、实现`JXPagerViewListViewDelegate`协议\n\n列表可以是任意类，UIView、UIViewController等等都可以，只要实现了`JXPagerViewListViewDelegate`协议就行。\n\n⚠️⚠️⚠️一定要保证`scrollCallback`的正确回调，许多朋友都容易疏忽这一点，导致异常，务必重点注意！\n\n下面的使用代码参考的是`TestListBaseView`类\n\n```Objective-C\n/**\n 返回listView。如果是vc包裹的就是vc.view；如果是自定义view包裹的，就是自定义view自己。\n */\n- (UIView *)listView {\n    return self;\n}\n\n/**\n 返回listView内部持有的UIScrollView或UITableView或UICollectionView\n 主要用于mainTableView已经显示了header，listView的contentOffset需要重置时，内部需要访问到外部传入进来的listView内的scrollView\n */\n- (UIScrollView *)listScrollView {\n    return self.tableView;\n}\n\n\n/**\n 当listView内部持有的UIScrollView或UITableView或UICollectionView的代理方法`scrollViewDidScroll`回调时，需要调用该代理方法传入的callback\n */\n- (void)listViewDidScrollCallback:(void (^)(UIScrollView *))callback {\n    self.scrollCallback = callback;\n}\n```\n\n### 4、列表回调处理\n\n`TestListBaseView`在其`tableView`的滚动回调中，通过调用上面持有的scrollCallback，把列表的滚动事件回调给JXPagerView内部。\n```Objective-C\n- (void)scrollViewDidScroll:(UIScrollView *)scrollView {\n    !self.scrollCallback ?: self.scrollCallback(scrollView);\n}\n```\n\n## 实现原理\n\n[实现原理](https://github.com/pujiaxin33/JXPagingView/blob/master/Document/JXPagingView%E5%8E%9F%E7%90%86.md)\n\n## `JXPagerSmoothView`\n\n如果你需要类似于**淘宝**、**转转**首页从顶部header用力往上滚动之后，下面的列表会跟着滚动的效果。因为`JXPagerView`的实现原理限制，当用户从顶部header的位置用力往上滚动，`JXPagerView`会在`JXCategoryView`刚好在顶部的时候突然停住。这个时候就需要使用`JXPagerSmoothView`，swift版本叫`JXPagingSmoothView`。\n\n因为与`JXPagerView`的原理完全不同，所以各自会有一些特性的区别，但是从使用体验来说，是完全一致的。具体使用细节请参考demo示例。\n\n实现原理参考[JXPagerSmoothView文章解析](https://juejin.im/post/5ddb2fe4f265da7def5424c7)\n\n\n## 特殊说明\n\n### JXCategoryView、JXSegmentedView\n悬浮的HeaderView，用的是我写的：[OC版本-JXCategoryView](https://github.com/pujiaxin33/JXCategoryView) 、[Swift版本-JXSegmentedView](https://github.com/pujiaxin33/JXSegmentedView)。几乎实现了所有主流效果，而且非常容易自定义扩展，强烈推荐阅读。\n\n\n### 头图缩放说明\n头图缩放原理，参考这个库：[JXTableViewZoomHeaderImageView](https://github.com/pujiaxin33/JXTableViewZoomHeaderImageView)\n\n### 列表下拉刷新说明\n\n需要使用`JXPagerListRefreshView`类（是`JXPagerView`的子类）\n\n### JXPagerListContainerType说明\n\nUIScrollView：优势：没有其他副作用。劣势：实时的视图内存占用相对大一点，因为所有加载之后的列表视图都在视图层级里面。\nUICollectionView：优势：因为列表被添加到cell上，实时的视图内存占用更少，适合内存要求特别高的场景。劣势：因为cell重用机制的问题，导致列表被移除屏幕外之后，会被放入缓存区，而不存在于视图层级中。如果刚好你的列表使用了下拉刷新视图，在快速切换过程中，就会导致下拉刷新回调不成功的问题。（使用MJRefresh会出现此问题）一句话概括：使用CollectionView的时候，就不要让列表使用下拉刷新加载。\n\n### 关于下方列表视图的代理方法`- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath`有时候需要点击两次才回调\n\n出现步骤：当手指放在下方列表视图往下拉，直到TableHeaderView完全显示。\n\n原因：经过上面的步骤之后，手指已经离开屏幕且列表视图已经完全静止，UIScrollView的isDragging属性却依然是true。就导致了后续的第一次点击，让系统认为当前UIScrollView依然在滚动，该点击就让UIScrollView停止下来，没有继续转发给UITableView，就没有转化成didSelectRow事件。\n\n解决方案：经过N种尝试之后，还是没有回避掉系统的`isDragging`异常为true的bug。大家可以在自定义cell最下方放置一个与cell同大小的button，把button的touchUpInside事件当做`didSelectRow`的回调。因为UIButton在响应链中的优先级要高于UIGestureRecognizer。\n\n代码：请参考`TestTableViewCell`类的配置。\n\n### 指定默认选中index\n\n默认显示index=2的列表，代码如下：\n```\nself.pagerView.defaultSelectedIndex = 2;\nself.categoryView.defaultSelectedIndex = 2;\n```\n\n### 顶部轮播图手势处理\n\n如果TableHeaderView添加了轮播图，获取其他可以横向滚动的UIScrollView。如果不处理，就会出现左右滚动轮播图的时候又可以触发整个页面的上下滚动。为了规避该问题，请参考示例仓库中`BannerViewController`类的处理方法。即可同一时间只允许左右滚动或者上下滚动。\n\n### 关于列表用UIViewController封装且要支持横竖屏的tips\n\n在列表UIViewController类里面一定要加上下面这段代码：(不要问我为什么，我也不知道，谁知道系统内部是怎么操作的，反正加上就没毛病了)\n```\n- (void)loadView {\n    self.view = [[UIView alloc] init];\n}\n```\n\n### `JXPagerSmoothView` header有UITextField或者`UITextView`\n详情参考OC版本示例【滚动延续 Header有输入框】\n\n列表自定义子类化`UITableView`或者`UICollectionView`，然后重载`scrollRectToVisible`方法，示例代码如下。\n```Object-C\n@implementation TestTableView\n- (void)scrollRectToVisible:(CGRect)rect animated:(BOOL)animated {\n    [self setContentOffset:CGPointMake(self.contentOffset.x, rect.origin.y) animated:animated];\n}\n@end\n```\n\n### `FDFullscreenPopGesture`等全屏手势兼容处理\n\n[全屏手势兼容处理文档，点击查看 ❗️❗️❗️](https://github.com/pujiaxin33/JXPagingView/blob/master/Document/%E5%85%A8%E5%B1%8F%E6%89%8B%E5%8A%BF%E5%A4%84%E7%90%86.md)\n\n### 侧滑手势处理\n[侧滑手势处理](./Document/侧滑手势处理.md)\n\n## 迁移指南\n- **0.0.9版本**：将下面两个API的返回值修改为了NSUInteger(swift版本为Int)，之前版本是CGFloat，升级为0.0.9及以上的时候，记得修改一下使用地方的返回值类型，不然会引起crash。\n  - `- (NSUInteger)heightForPinSectionHeaderInPagerView:(JXPagerView *)pagerView`\n  - `- (NSUInteger)tableHeaderViewHeightInPagerView:(JXPagerView *)pagerView`\n- **1.0.0版本**：\n  删除代理方法`- (NSArray \u003cid\u003cJXPagerViewListViewDelegate\u003e\u003e *)listViewsInPagerView:(JXPagerView *)pagerView;`，请参考示例使用下面两个代理方法:\n  - `- (NSInteger)numberOfListsInPagerView:(JXPagerView *)pagerView;`\n  - `- (id\u003cJXPagerViewListViewDelegate\u003e)pagerView:(JXPagerView *)pagerView initListAtIndex:(NSInteger)index;`\n- **2.0.0版本**：`JXPagerListContainerView`进行了重构，列表拥有了完整的生命周期方法。列表是`UIViewController`类，`viewWillAppear`等生命周期方法将会正确触发。\n- \n    - 删除了collectionView，用`scrollView`属性替换。\n    - 和`CategoryView`的联动绑定代码更新为`self.categoryView.listContainer = (id\u003cJXCategoryViewListContainer\u003e)self.pagerView.listContainerView;`。\n    - `JXPagerView`新增`- (instancetype)initWithDelegate:(id\u003cJXPagerViewDelegate\u003e)delegate listContainerType:(JXPagerListContainerType)type`初始化方法，可以指定列表容器为`UIScrollView`或者`UICollectionView`；\n    \n\n## 补充\n\n有不明白的地方，建议多看下源码。再有疑问的，欢迎提Issue交流🤝\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpujiaxin33%2Fjxpagingview","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpujiaxin33%2Fjxpagingview","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpujiaxin33%2Fjxpagingview/lists"}