filesbox/app/filesbox_ios/FilesBox/Pods/JXPagingView
2023-09-21 10:53:23 +08:00
..
Sources/JXPagerView xiaochengxu 2023-09-21 10:53:23 +08:00
LICENSE xiaochengxu 2023-09-21 10:53:23 +08:00
README.md xiaochengxu 2023-09-21 10:53:23 +08:00

JXPagingView

类似微博主页、简书主页、QQ联系人页面等效果。多页面嵌套既可以上下滑动也可以左右滑动切换页面。支持HeaderView悬浮、支持下拉刷新、上拉加载更多。

功能特点

  • 支持OC与Swift;
  • 支持列表懒加载,等到列表真正显示的时候才加载,而不是一次性加载所有列表;
  • 支持首页下拉刷新、列表视图下拉刷新、列表视图上拉加载更多;
  • 支持悬浮SectionHeader的垂直位置调整
  • 支持从顶部用力往上滚动,下面的列表会跟着滚动,而不会突然卡主,需要使用JXPagerSmoothView类;
  • 列表封装简洁,只要遵从JXPagingViewListViewDelegate协议即可。UIView、UIViewController等都可以
  • 使用JXCategoryView/JXSegmentedView分类控制器几乎支持所有主流效果、高度自定义、可灵活扩展
  • 支持横竖屏切换;
  • 支持点击状态栏滚动当前列表到顶部;
  • 支持列表显示和消失的生命周期方法;
  • isListHorizontalScrollEnabled属性控制列表是否可以左右滑动默认YES
  • 支持FDFullscreenPopGesture等全屏手势兼容处理;

预览

效果 预览图
头图缩放
参考ZoomViewController
Zoom
主页下拉刷新&列表上拉加载更多
参考RefreshViewController
Refresh
列表下拉刷新
参考ListRefreshViewController
Refresh
悬浮sectionHeader位置调整 Refresh
导航栏隐藏
参考NaviBarHiddenViewController
Refresh
CollectionView列表示例
参考CollectionViewViewController.swift
只有swift的demo工程有该示例
Refresh
HeaderView更新高度示例
参考HeightChangeAnimationViewController.swift
只有swift demo工程才有该示例
Refresh
PagingView嵌套CategoryView
参考NestViewController
只有 OC!OC!OC! 的demo工程才有该示例
操作比较特殊,如果需要此效果,
请认真参考源码,有问题多试试
参考NestViewController.h类
Nest
CategoryView嵌套PagingView
参考NestViewController.swift
只有 Swift!Swift!Swift! 的demo工程才有该示例
操作比较特殊,如果需要此效果,
请认真参考源码,有问题多试试
参考NestViewController.swift类
Nest
点击状态栏 Zoom
横竖屏旋转 Zoom
JXPageListView
顶部需要自定义cell的场景类似于电商APP首页滑动到列表最底部才是分类控制器
该效果是另一个库,点击查看JXPageListView
该效果是另一个库,点击查看JXPageListView
该效果是另一个库,点击查看JXPageListView
list
JXPagerSmoothView
类似淘宝、转转首页
从顶部用力往上滚动,下面的列表会继续滚动
smooth

安装

手动

Swift版本 Clone代码拖入JXPagingView-Swift文件夹使用JXPagingView类;

OC版本 Clone代码拖入JXPagerView文件夹使用JXPagerView类;

CocoaPods

  • Swift版本

支持swift版本5.0+

target '<Your Target Name>' do
    pod 'JXPagingView/Paging'
end
  • OC版本
target '<Your Target Name>' do
    pod 'JXPagingView/Pager'
end

Swift与OC的仓库地址不一样请注意选择

pod repo update然后再pod install

使用

swift版本使用类似只是类名及相关API更改为JXPagingView具体细节请查看Swfit工程。

1、初始化JXCategoryTitleViewJXPagerView

self.categoryView = [[JXCategoryTitleView alloc] initWithFrame:frame];
//配置categoryView细节参考源码

self.pagerView = [[JXPagerView alloc] initWithDelegate:self];
[self.view addSubview:self.pagerView];

//⚠将pagerView的listContainerView和categoryView.listContainer进行关联这样列表就可以和categoryView联动了。⚠
self.categoryView.listContainer = (id<JXCategoryViewListContainer>)self.pagerView.listContainerView;

Swift版本列表关联代码

//给JXPagingListContainerView添加extension表示遵从JXSegmentedViewListContainer的协议
extension JXPagingListContainerView: JXSegmentedViewListContainer {}
//⚠将pagingView的listContainerView和segmentedView.listContainer进行关联这样列表就可以和categoryView联动了。⚠
segmentedView.listContainer = pagingView.listContainerView

2、实现JXPagerViewDelegate协议

/**
 返回tableHeaderView的高度因为内部需要比对判断只能是整型数
 */
- (NSUInteger)tableHeaderViewHeightInPagerView:(JXPagerView *)pagerView {
    return JXTableHeaderViewHeight;
}

/**
 返回tableHeaderView
 */
- (UIView *)tableHeaderViewInPagerView:(JXPagerView *)pagerView {
    return self.userHeaderView;
}


/**
 返回悬浮HeaderView的高度因为内部需要比对判断只能是整型数
 */
- (NSUInteger)heightForPinSectionHeaderInPagerView:(JXPagerView *)pagerView {
    return JXheightForHeaderInSection;
}


/**
 返回悬浮HeaderView
 */
- (UIView *)viewForPinSectionHeaderInPagerView:(JXPagerView *)pagerView {
    return self.categoryView;
}

/**
 返回列表的数量
 */
- (NSInteger)numberOfListsInPagerView:(JXPagerView *)pagerView {
    //和categoryView的item数量一致
    return self.titles.count;
}

/**
 根据index初始化一个对应列表实例。注意一定要是新生成的实例
 只要遵循JXPagerViewListViewDelegate即可无论你返回的是UIView还是UIViewController都可以。
 */
- (id<JXPagerViewListViewDelegate>)pagerView:(JXPagerView *)pagerView initListAtIndex:(NSInteger)index {
    TestListBaseView *listView = [[TestListBaseView alloc] init];
    if (index == 0) {
        listView.dataSource = @[@"橡胶火箭", @"橡胶火箭炮", @"橡胶机关枪"...].mutableCopy;
    }else if (index == 1) {
        listView.dataSource = @[@"吃烤肉", @"吃鸡腿肉", @"吃牛肉", @"各种肉"].mutableCopy;
    }else {
        listView.dataSource = @[@"【剑士】罗罗诺亚·索隆", @"【航海士】娜美", @"【狙击手】乌索普"...].mutableCopy;
    }
    [listView beginFirstRefresh];
    return listView;
}

3、实现JXPagerViewListViewDelegate协议

列表可以是任意类UIView、UIViewController等等都可以只要实现了JXPagerViewListViewDelegate协议就行。

⚠️⚠️⚠️一定要保证scrollCallback的正确回调,许多朋友都容易疏忽这一点,导致异常,务必重点注意!

下面的使用代码参考的是TestListBaseView

/**
 返回listView。如果是vc包裹的就是vc.view如果是自定义view包裹的就是自定义view自己。
 */
- (UIView *)listView {
    return self;
}

/**
 返回listView内部持有的UIScrollView或UITableView或UICollectionView
 主要用于mainTableView已经显示了headerlistView的contentOffset需要重置时内部需要访问到外部传入进来的listView内的scrollView
 */
- (UIScrollView *)listScrollView {
    return self.tableView;
}


/**
 当listView内部持有的UIScrollView或UITableView或UICollectionView的代理方法`scrollViewDidScroll`回调时需要调用该代理方法传入的callback
 */
- (void)listViewDidScrollCallback:(void (^)(UIScrollView *))callback {
    self.scrollCallback = callback;
}

4、列表回调处理

TestListBaseView在其tableView的滚动回调中通过调用上面持有的scrollCallback把列表的滚动事件回调给JXPagerView内部。

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    !self.scrollCallback ?: self.scrollCallback(scrollView);
}

实现原理

实现原理

JXPagerSmoothView

如果你需要类似于淘宝转转首页从顶部header用力往上滚动之后下面的列表会跟着滚动的效果。因为JXPagerView的实现原理限制当用户从顶部header的位置用力往上滚动JXPagerView会在JXCategoryView刚好在顶部的时候突然停住。这个时候就需要使用JXPagerSmoothViewswift版本叫JXPagingSmoothView

因为与JXPagerView的原理完全不同所以各自会有一些特性的区别但是从使用体验来说是完全一致的。具体使用细节请参考demo示例。

实现原理参考JXPagerSmoothView文章解析

特殊说明

JXCategoryView、JXSegmentedView

悬浮的HeaderView用的是我写的OC版本-JXCategoryViewSwift版本-JXSegmentedView。几乎实现了所有主流效果,而且非常容易自定义扩展,强烈推荐阅读。

头图缩放说明

头图缩放原理,参考这个库:JXTableViewZoomHeaderImageView

列表下拉刷新说明

需要使用JXPagerListRefreshView类(是JXPagerView的子类)

JXPagerListContainerType说明

UIScrollView优势没有其他副作用。劣势实时的视图内存占用相对大一点因为所有加载之后的列表视图都在视图层级里面。 UICollectionView优势因为列表被添加到cell上实时的视图内存占用更少适合内存要求特别高的场景。劣势因为cell重用机制的问题导致列表被移除屏幕外之后会被放入缓存区而不存在于视图层级中。如果刚好你的列表使用了下拉刷新视图在快速切换过程中就会导致下拉刷新回调不成功的问题。使用MJRefresh会出现此问题一句话概括使用CollectionView的时候就不要让列表使用下拉刷新加载。

关于下方列表视图的代理方法- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath有时候需要点击两次才回调

出现步骤当手指放在下方列表视图往下拉直到TableHeaderView完全显示。

原因经过上面的步骤之后手指已经离开屏幕且列表视图已经完全静止UIScrollView的isDragging属性却依然是true。就导致了后续的第一次点击让系统认为当前UIScrollView依然在滚动该点击就让UIScrollView停止下来没有继续转发给UITableView就没有转化成didSelectRow事件。

解决方案经过N种尝试之后还是没有回避掉系统的isDragging异常为true的bug。大家可以在自定义cell最下方放置一个与cell同大小的button把button的touchUpInside事件当做didSelectRow的回调。因为UIButton在响应链中的优先级要高于UIGestureRecognizer。

代码:请参考TestTableViewCell类的配置。

指定默认选中index

默认显示index=2的列表代码如下

self.pagerView.defaultSelectedIndex = 2;
self.categoryView.defaultSelectedIndex = 2;

顶部轮播图手势处理

如果TableHeaderView添加了轮播图获取其他可以横向滚动的UIScrollView。如果不处理就会出现左右滚动轮播图的时候又可以触发整个页面的上下滚动。为了规避该问题请参考示例仓库中BannerViewController类的处理方法。即可同一时间只允许左右滚动或者上下滚动。

关于列表用UIViewController封装且要支持横竖屏的tips

在列表UIViewController类里面一定要加上下面这段代码(不要问我为什么,我也不知道,谁知道系统内部是怎么操作的,反正加上就没毛病了)

- (void)loadView {
    self.view = [[UIView alloc] init];
}

JXPagerSmoothView header有UITextField或者UITextView

详情参考OC版本示例【滚动延续 Header有输入框】

列表自定义子类化UITableView或者UICollectionView,然后重载scrollRectToVisible方法,示例代码如下。

@implementation TestTableView
- (void)scrollRectToVisible:(CGRect)rect animated:(BOOL)animated {
    [self setContentOffset:CGPointMake(self.contentOffset.x, rect.origin.y) animated:animated];
}
@end

FDFullscreenPopGesture等全屏手势兼容处理

全屏手势兼容处理文档,点击查看

迁移指南

  • 0.0.9版本将下面两个API的返回值修改为了NSUInteger(swift版本为Int)之前版本是CGFloat升级为0.0.9及以上的时候记得修改一下使用地方的返回值类型不然会引起crash。
    • - (NSUInteger)heightForPinSectionHeaderInPagerView:(JXPagerView *)pagerView
    • - (NSUInteger)tableHeaderViewHeightInPagerView:(JXPagerView *)pagerView
  • 1.0.0版本 删除代理方法- (NSArray <id<JXPagerViewListViewDelegate>> *)listViewsInPagerView:(JXPagerView *)pagerView;,请参考示例使用下面两个代理方法:
    • - (NSInteger)numberOfListsInPagerView:(JXPagerView *)pagerView;
    • - (id<JXPagerViewListViewDelegate>)pagerView:(JXPagerView *)pagerView initListAtIndex:(NSInteger)index;
  • 2.0.0版本JXPagerListContainerView进行了重构,列表拥有了完整的生命周期方法。列表是UIViewController类,viewWillAppear等生命周期方法将会正确触发。
    • 删除了collectionViewscrollView属性替换。
    • CategoryView的联动绑定代码更新为self.categoryView.listContainer = (id<JXCategoryViewListContainer>)self.pagerView.listContainerView;
    • JXPagerView新增- (instancetype)initWithDelegate:(id<JXPagerViewDelegate>)delegate listContainerType:(JXPagerListContainerType)type初始化方法,可以指定列表容器为UIScrollView或者UICollectionView

补充

有不明白的地方建议多看下源码。再有疑问的欢迎提Issue交流🤝