Git Product home page Git Product logo

jxpagingview's Introduction

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已经显示了header,listView的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刚好在顶部的时候突然停住。这个时候就需要使用JXPagerSmoothView,swift版本叫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等生命周期方法将会正确触发。
    • 删除了collectionView,用scrollView属性替换。
    • CategoryView的联动绑定代码更新为self.categoryView.listContainer = (id<JXCategoryViewListContainer>)self.pagerView.listContainerView;
    • JXPagerView新增- (instancetype)initWithDelegate:(id<JXPagerViewDelegate>)delegate listContainerType:(JXPagerListContainerType)type初始化方法,可以指定列表容器为UIScrollView或者UICollectionView

补充

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

jxpagingview's People

Contributors

muxinqi avatar pujiaxin33 avatar slwhh avatar superk589 avatar yanpengimp avatar ym-bh avatar zhwayne avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

jxpagingview's Issues

demo中的小问题&一些建议

demo中需要改一下判断scrollCallback

 if(scrollView == self.tableView && self.scrollCallback){
        self.scrollCallback(scrollView);
    }

另外,对比其他的框架
我决定要是用你的框架,
类似的框架或多或少有些不足,
你的也有,不过少很多.

  1. listview如果能放在controller中初始化就好了,YNPageViewController中就是
  2. 尽量支持 autolayout

希望你做的更好~

左右滚动pin headerview高度问题

@pujiaxin33 你好,使用了你的这个库解决了页面布局的一些问题,谢谢。
同时有个问题想请教,就是在左右滚动切换时,如果pin headerview需要动态的调整高度,如何处理?
如图,比如节目和生活下pin headerview是80,当切换到动态下时为45,这时候需要怎么调整一下?谢谢!

image

缓存

有五个item,直接点击第五个,会看到中间的界面,如果有很多个item,会不会很占用内存

遇到一个刷新的问题

作者您好:
我在使用这个库的时候,在TestListView中设置刷新的时候,我想一进来就刷新一次,然后在点击title的时候也能够刷新,问题来了,在三个title的时候,点击中间的那个,会把第三个或者第一个也一起刷新了,虽然好像预加载了,但是我不需要这个功能该怎么解决?还望回复一下

5s 上的不能滚动

当头部视图的高度为小数时,在 ipone5s 模拟器上,listViews里面的滑动视图滚动不了

请问怎样点击状态栏滚动到顶部

设置了currentScrollingListView的scrollsToTop,但是只有HeaderView可见时才能滚到到顶部,滑动范围超过HeaderView的高度接不能滚到顶部了。
谢谢。

这种效果怎么实现。。

![Uploading IMG_1282.GIF…]
请问一下这个怎么实现,oc版demo中能加一个吗???或者说一下思路也行。。谢了。。。

自定义悬浮HeaderView的问题

@pujiaxin33 你好,先感谢你的这个库,写的挺好。。然后请教你个问题哈,就是我自定义了一个悬浮headerview,上面有2个按钮,我在切换俩按钮的时候怎么触发下面listview的切换,或者切换下面的listview怎么选中headerview上的某个按钮?谢谢!

动态PinSectionHeader高度问题

@pujiaxin33 请教个问题,就是点击切换不同标签选项时,pageView reloadData后高度变短了,出现了黑边。如图,点击节目时PinSectionHeader=80然后再切换回来点击了动态PinSectionHeader=45,分别设置PinSectionHeader后,pageView reloadData后出现了黑边。。

image

怎么判断当前是哪一个listview&其他的疑问?

  1. 如何判断当前是哪一个listview
    貌似你现在写的currentScrollingListView这个属性,需要在listview上下滑动一下才能知道.
- (void)listViewDidScroll:(UIScrollView *)scrollView {
    self.currentScrollingListView = scrollView;
    [self preferredProcessListViewDidScroll:scrollView];
}
  1. 跟第一个问题有点相关, 能不能弄一个回调,或者代理,告诉 滚到了第几个listview这个事件
    在你的uicollectionview的手指离开屏幕后的事件有个代理(scrollview的代理),貌似可以处理这个问题.

hi

oc怎么用?继承还是push推出?

由于多个scrollview的嵌套,点击statusBar不能正确的滚动到顶部

scrollView 属性:
open var scrollsToTop: Bool // default is YES.
注释是:
When the user taps the status bar, the scroll view beneath the touch which is closest to the status bar will be scrolled to top, but only if its scrollsToTop property is YES, its delegate does not return NO from -scrollViewShouldScrollToTop:, and it is not already at the top. On iPhone, we execute this gesture only if there's one on-screen scroll view with scrollsToTop == YES. If more than one is found, none will be scrolled.

// -------------------------------------------------------

首先非常感谢作者写了该开源项目,在实际的项目中节约了很多时间。

有一个问题:

如果子item也滚动到顶部的话,此时点击 status bar 是没有反应的,因为 mainTableView 和该 itemScrollView 的 scrollsToTop 都是true, 系统不知道处理哪一个了。希望题主可以把这个小issue加进去😄。

我在实际项目的处理方式是:

1 在 AppDelegate.swift 添加通知:

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    super.touchesBegan(touches, with: event)
    if let touch = touches.first {
        let statusBarHeight = xxxxxx
        if touch.location(in: nil).y > statusBarHeight {
            return
        }
        NotificationCenter.default.post(name: notificationName, object: nil)
    }
}

2 在相关的ViewController设置:

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    
    NotificationCenter.default.addObserver(self, selector: #selector(scrollToTopNoti), name: .notificationName, object: nil)
}

@objc private func scrollToTopNoti() {
    item0.scrollView.contentOffset = .zero
    item1.scrollView.contentOffset = .zero
    item2.scrollView.contentOffset = .zero
    
    pagingView.mainTableView?.scrollRectToVisible(topFrame, animated: true)
} 

这样处理以后点击status bar 就能正常滚动到顶部了,希望题主可以考虑一下怎样在pods实现类似的功能。

如果列表是collectionView时,滑动异常

大佬,如果列表是collectionView时,上滑到collectionView部门内容超出边界后( categoryView 悬浮停靠后继续上滑了一段距离), 往下滑时collectionView 的contentOffset的y值突然变为0,是什么原因呀?而且上下滑动时很容易左右滑动

下载了,打不开

弹出Failed to load project at '/Users/goopai/Downloads/JXPagingView-master/JXPagingView.xcodeproj', incompatible project version.

delegate问题

  • (CGFloat)tableHeaderViewHeightInPagerView:(JXPagerView *)pagerView
    这个代理 应该必须要传一个整数。不能属于自计算的。

超出titleView 上面的按钮怎么相应点击事件???

simulator screen shot - iphone 8 plus - 2018-11-14 at 15 47 32
画红色圈圈的按钮,不相应点击事件,我已经做过

  • (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    UIView *view = [super hitTest:point withEvent:event];
    if (view == nil) {
    for (UIView *subView in self.subviews) {
    CGPoint tp = [subView convertPoint:point fromView:self];
    if (CGRectContainsPoint(self.btnFollow.bounds, tp)) {
    view = self.btnFollow;
    } else if (CGRectContainsPoint(self.btnServe.bounds, tp)) {
    view = self.btnServe;
    } else if (CGRectContainsPoint(self.btnMore.bounds, tp)) {
    view = self.btnMore;
    } else if (CGRectContainsPoint(self.btnClose.bounds, tp)) {
    view = self.btnClose;
    }

      }
    

    }
    return view;
    }
    还是点击不到???请问问什么??

屏幕边缘左滑手势

当tab非第一个时,屏幕边缘左滑手势无效,需要滑到第一个tab时才可以继续左滑返回。。。

使用哪个库的疑问

你好,感谢作者的开源,有几点小疑问:
1、如果我想使用带有头部高度可以改变的效果,只使用JXCategoryView可以吗,还是说需要JXCategoryView和JXPagingView一起pod进来
2、swift跟oc版本代码同步吗

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.