iOS初学者iOS技术交流iOS 开发每天分享优质文章

iOS 可添加Header的多控制器横向滑动列表(XDSlide

2018-08-17  本文已影响41人  上北以北

很多人会有这么个需求,一个带有header的列表,可以上下滚动同时又可以横向滚动切换到不同的页面(具体样子看文章末尾的效果图)。很多人在看到这个效果时会觉得这个很简单,但仔细想时又有点不知从何下手去写。
首先强调一点,不到万不得已,千万不要打手势的主意
看到这个效果你也许会想到tableview的嵌套,然后通过不同时机切换手势去实现。有这个想法的人我劝你往下看。
因为tableview在滚动过程中把手势切换给另一个tableview不管你做了多么周详的优化,也必然会有一个小小的卡顿,这个卡顿会成为你不可逾越的鸿沟。
所以遇到这类效果实现时我们不应该打手势的主意,而是要考虑联动,通过界面的联动绕过手势。
从这个角度出发,先讲一下原理,然后给出XDSlideView的使用方法

原理

1, 先创建一个view,姑且叫它slideView吧
2, 再创建一个scrollView 用于装子tableView(这里只是为了说明原理,项目是子控制的view),就叫他pagesContener吧
3,再创建一个view, 用于盛放header和标题栏,这里就叫他headerContener吧

以上三个view便是这个效果所需要的所有东西,接下来我们把它们组装起来就OK了。
设置pagesContener 中子tableView 的 宽高 和 pagesContener 相等
然后根据 pagesContener 中子tableView 的个数设置 pagesContener 的 contentSize
然后把子tableView从左到右依次放到索引对应的位置
然后设置 pagesContener.pagingEnabled = YES
到这里,我们已经实现了横向滑动翻页效果,这是不是很容易

接下来设置pagesContener.bounds = slideView.bounds
然后把pagesContener 添加到 slideView
这个时候由于pagesContener 的高度 和 slideView 相同,所以默认情况下pagesContener的纵向滑动是禁止的,这也正是我们想要的。所以此时只有pagesContener 的 子tableView有纵向滑动
完成这一步我们只是把pagesContener 放到了另一个view中还是只是实现了横向滑动翻页效果,但是此时已经有了质的变换了,别急,接着往下看。

接下来设置headerContener的宽度 和 slideView 相同,高度 = header + 标题栏,假设高为 H 吧
设置headerContener.frame 的x值和y值 为 0
然后把headerContener 添加到 slideView (注意,这里一定要加到slideView上,而不是pagesContener上,这样由于headerContener 和pagesContener 都在slideView上,所以他们互不影响,当pagesContener横向滑动时headerContener不受其影响)
此时headerContener 在 slideView 的顶部
到此我们已经有一个带有header 并且 可以横向滑动的 列表了,一切都很简单,但这个列表还有些问题,首先这个headerContener不会滚动,而且还盖住了pagesContener的一部分内容

接下来就是重点了,我们先来解决内容遮盖这个问题
其实headerContener 遮盖的是 pagesContener 子tableview 的内容,由于子tableView的bounds需要和pagesContener 相等,所以不能更改子tableView的frame来解决,所以只有一个办法,那就是更改子tableView的contentInset 让其contentInset.top = H(还记得这是谁的高度吧,如果不记得那你肯定没看懂)
这样一来内容遮盖这个问题就完美解决了。

到此headerContener 还是只能待在slideView的顶端,这不是我们想要的,接下来就要用到整个项目的核心思想了——联动。
通过上面的一系列操作,目前能够纵向滚动的就只剩下pagesContener的子tableView了。我们通过KVO去监听pagesContener当前窗口显示的子tableView的contentOffset,通过所监听tableView的contentOffset.y 的值去 更改headerContener的frame.origin.y的值。同时同步其它子tablView的contentOffset(如果需要同步的话)

以上就是这个效果的基本原理,剩下的就是一些具体操作了,比如子控制中子view的处理,headerContener的变动范围的设定,KVO监听的处理,缓存处理,标题栏和页面联动处理等

内容有点多,如果没看懂也没关系,因为我已经写好了,用起来很简单。具体使用请看下面的使用方法。

使用方法

在GitHub:https://github.com/Xiexingda/XDSlideView 下载
或者使用cocoapods pod "XDSlideView"
把XDSlideView文件放入项目中

1,导入头文件,并添加代理XDSlideViewDataSourceAndDelegate

#import "XDSlideView.h"
@interface ViewController ()<XDSlideViewDataSourceAndDelegate>

2,创建一个标题数组,切记数组中不能有重复名字

//很关键,数组中的名字不能有重复项
_titles = @[@"page_0",@"page_1",@"page_2",@"page_3",@"page_4",@"page_5",@"page_6",@"page_7",@"page_8"];

3, 添加slideview

//创建slideView, 后面的参数一定要为当前页self
_slide = [[XDSlideView alloc]initWithFrame:rect dataSourceAndDelegateInBaseCongtroller:self];

//设置起始页,默认为0
//_slide.beginPage = 1;

//设置barItem大小,默认为80*40
//_slide.slideBarItemSize = CGSizeMake(80, 50);

//设置缓存数(最大同时存在页数),默认为50
//_slide.cacheNumber = 10;

//设置时候有横向反弹效果,默认为NO
//_slide.slideBounces = NO;

//设置标题大小,默认为16
//_slide.slideBartextFont = 18;

//设置选中时的标题颜色,默认为橘黄
_slide.slideBarHighlightTintColor = [UIColor blueColor];

//设置默认标题颜色,默认为黑色
_slide.slideBarDefaultTintColor = [UIColor grayColor];

//设置标题栏背景颜色,默认白色
_slide.slideBarBackColor = [UIColor cyanColor];

//添加header,不加header为标题栏吸顶状态
UIView *view = [[UIView alloc]initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 200)];
view.backgroundColor = [UIColor yellowColor];
_slide.headerView = view;

[self.view addSubview:_slide];

5, 必须实现两个代理XDSlideViewPageTitles 和 XDSlideViewChildControllerToSlideView: forIndex:

- (NSArray<NSString *> *)XDSlideViewPageTitles {
return _titles;
}

- (UIViewController *)XDSlideViewChildControllerToSlideView:(XDSlideView *)slideView forIndex:(NSInteger)index {

//复用
UIViewController *pageVc = [slideView dequeueReusablePageForIndex:index];

if (!pageVc) {
//这里可以通过自定义控制器的init实现控制器传参,用于控制器的review(注意*该控制器的子View内必须要有一个可滚动的view)
pageVc = [[Page alloc]initWithTag:index];

/*
如果控制器不同,可以通过索引,或者title分别返回
if (index == 0) {
pageVc = [[Page alloc]initWithTag:index];
} else {
pageVc = [[Page_other alloc]initWithTag:index];
}
*/
}

return pageVc;
}

6, 如果需要的话可以实现页面切换监听代理

#pragma mark -- 非必须实现代理
- (void)XDSlideViewDidChangeToPageByName:(NSString *)pageName pageIndex:(NSInteger)pageIndex {
    //页面已经变化时调用
    NSLog(@"XDSlideViewDidToTitle:%@ --- index: %ld",pageName, pageIndex);
}

效果图

XDSlideView.gif

GitHub:https://github.com/Xiexingda/XDSlideView

上一篇下一篇

猜你喜欢

热点阅读