iOS工作系列iOS移动开发开发

iOS:实现一个横向的tableView 理解scrollVie

2015-08-22  本文已影响3734人  redihd

HorizontalTableView相关的(下面还有对于scrollView的讨论)

上次写了一篇实现横向pageView的文章,地址在这里,本来是想把上次的pageView补全的,后来想想不如直接写一个横向的tableView好了。于是就有了这篇文章。
先上代码,github地址在这,再看demo 效果

ZqwHorizontalTableViewDemo.gif

其实横向的tableView的实现基本和上次的pageView差不多,主要需要的也就是一个复用cell池可视cell池并及时更新他们。
与pageView相比只是多了一个cellIdentifiy来取对应的cell,另一个就是如何获取现在可视区域的cell及对应的位置(因为现在每一个cell的宽度不一定了)。

所以比起上次的pageView,我们只要获取现在要显示的cells开始index和一共有几个cell需要展示,在这里我们用一个range来表示他们,然后根据range来判断要显示cell的和不显示的cell并对 visibleListViewsItems 和 dequeueViewPool 做更新,然后计算要显示的cell的位置,这样子一个有复用功能的横向的tableView就搞定了。

而另外一个多出来的需求cellIdentifiy 就需要我们新建一个属于自己的baseCell来配合,我们该cell带一个identifiy属性,在从复用池(dequeueViewPool)获取cell的时候对identifiy做一次判断,如果有对应cell的identifiy则取出,没有则新建即可。

这次我并没有使用block,主要是上次复用view的返回用block之后发现返回需要的cell那一部分太大段了,还不如分开来写。而且这样也更好地模仿了系统的tableView,所以我也设了一个dataSource 和一个actionDelegate(我想用delegate来着),但是。。。delegate已经被scrollView用了。

这里上一下我们的HorizontalTableView的数据源,代理和几个简单地方法

//@property (nonatomic, weak) id<ZqwTableViewDelegate> actionDelegate;   最基本的处理点击事件
- (void) zqwTableView:(ZqwHorizontalTableView*)tableView didTapAtColumn:(NSInteger)column;

//@property (nonatomic, weak) id<ZqwTableViewDataSource> dataSource;  1、 多少个cell 2、 对应的宽度 3、 获取cell
- (NSInteger)numberOfColumnsInZqwTableView:(ZqwHorizontalTableView *)tableView;

- (ZqwTableViewCell *)zqwTableView:(ZqwHorizontalTableView *)tableView cellAtColumn:(NSInteger)column;

- (CGFloat)zqwTableView:(ZqwHorizontalTableView *)tableView cellWidthAtColumn:(NSInteger)column;

@interface ZqwHorizontalTableView : UIScrollView
- (ZqwTableViewCell *)dequeueZqwTalbeViewCellForIdentifiy:(NSString *)identifiy;

- (void)reloadData;

具体如何使用可以看git上的demo

另外再上一个scrollView相关的

顺便附上一个自己实现一部分功能的scrollView
git地址在这里
这个demo主要就是为了演示scrollView的工作原来,为什么scroll能拖动,所谓的contentOffset,和contentSize代表着什么。

  1. scrollView 为什么能滚动.我们知道每个视图都有一个 bounds和 frame。当我们要去布局一个界面时,我们需要处理视图的 frame。这个属性允许我们设置视图的位置和大小。视图的 frame 和 bounds 的大小总是一样的,但是他们的 origin 有可能不同。弄懂这两个属性的工作原理是理解 UIScrollView 的关键。

    先放出两个公式
    viewPosition.x = View.frame.origin.x - Superview.bounds.origin.x;
    viewPosition.y = View.frame.origin.y - Superview.bounds.origin.y;

    现在有一个父视图和若干个子视图,一般情况,父视图的bounds.origin都是(0,0),子视图的位置则是frame相对于bounds.origin(0,0)的位置,一般子视图的动画或者移动,都是对子视图frame的改变。
    现在我们来观察scrollView,移动scrollView的时候所有的子视图的位置好像都改变了。如果我们想要改变子视图的frame来做出这种效果,我们需要同时调整所有子视图的frame。这样操作量太大,这时候来看我们之前的公式,想要改变位置,不一定要改变子视图的frame,而通过改变父视图的bounds来实现。

    所以,改变scrollView的bounds就是我们滑动scrollView的本质。

  2. contentOffset 是scrollView特有的一个属性,但其实我们通过上面的分析可以很快的了解到,这个属性的实质就是bounds.origin。这里贴一下contentOffset的setter 和 getter方法。

    - (void)setContentOffset:(CGPoint)offset{
        CGRect bounds = [self bounds];
        bounds.origin = offset;
        [self setBounds:bounds];
    }
    
    - (CGPoint)contentOffset{
        return self.bounds.origin;
    }
    
  3. contentSize 这个属性是规定了scrollView可滚动区域的属性。当contentSize小于bounds.size时则不能滑动,当contentSize大于bounds.size时则可滑动,对应的contentOffset的最大值等于contentSize减去对应的bounds.size。

我写的scrollView的demo只是简单实现了scrollView滑动的功能,其他的属性比如减速,bounces这些增强使用体验的效果我们可以用facebook的pop来实现,这里就不细聊了。

欢迎讨论~

上一篇下一篇

猜你喜欢

热点阅读