要实现的目标效果图:
目标效果拆解分析(demo地址):
1、左右滑动时,保证第一列固定不动,右侧的列表可以根据手势进行左右滑动;
2、当左右滑动自然减速到0时,需要根据右侧列表的位置偏移情况,决定是否需要进行自动位置矫正,以便完整的显示某一列;
3、上下滑动时,整个列表都进行上下滑动,保证列表滑动的流畅性;
4、表格的数据刷新和单元格的显示,提供和系统TableView相一致的方法;
5、表头部分支持可配置的点击事件;
实现分析:
1、要保证左右滑动时,左侧数据固定不动、右侧的数据可以左右滑动,实现的方式应该有多种;这里直接使用左右各一个TableView的方式实现,左边TableView为固定列,右侧TableView为可以左右滑动的表格;
直观的感受是直接使用一个TableView,在TableView的cell上添加ScrollView,就可以达到类似的效果,但实际上这种方式存在一些比较不合理的地方;下面对这种方式做一个简单的分析:
a、滚动cell上的ScrollView时,需要让屏幕内所有cell都以相同的频率滚动;这里的处理比较复杂,可以参考的方式是抛出cell上的offset,然后对表格进行刷新,把offset的值传递给所有的cell,这需要不间断的对表格进行刷新操作,引起页面性能问题,处理不好还会引起死循环;
b、ScrollView属于比较重量级的控件,在cell上添加ScrollView内存消耗较大,容易造成页面的性能问题;
c、每一处需要这种效果的页面,都需要通过定制包含ScrollView的cell的方式去实现,实现复用的难度较大;
2、左右滑动减速到0时自动位置矫正的实现,通过ScrollView的代理方法:`scrollViewDidEndDragging` 与 scrollViewDidEndDecelerating 来实现当滚动停止时需要做的位置偏移;通过计算当前的水平方向的offset 与 右表的列宽的之间的位置关系决定偏移的大小;
3、滑动时保证列表的流畅性,通过在scrollViewDidScroll 代理方法内部去实现,在代理方法中通过同步修改左右表的bounds来实现上下滚动时,左右表的同步滚动;这里需要注意的是不能调用setContentOffset来同步位置偏移,这可能会引起死循环,原因是setContentOffset方法修改ScrollView的位置偏移时会回掉scrollViewDidScroll方法;
4、多表的数据刷新通过自定义的reloadData方法实现,在reloadData方法里直接调用左右两个表格的系统reloadData方法,并由系统的TableView代理方法抛出多表的同步代理方法,通过tag区分左表与右表;
- (void)reloadData {
[self.leftTableView reloadData];
[self.rightTableView reloadData];
}
5、表头部分支持可配置的点击事件,主要通过在表头的ScrollView上添加Button的响应事件达到效果;
其他细节
其他实现的细节点包括:
1、在右表发生左右滑动出现位置偏移后,上下滑动时要保证滚动条贴边显示,即需要计算并设置scrollIndicatorInsets的值;
2、控制上下滑动与左右滑动的事件区分,保证表格根据用户的滑动方式做出正确的响应;这部分通过控制多表内部的子视图层级关系,以及相关滚动子视图的contentSize来实现;通过contentSize可以控制ScrollView(TableView)的某一个方向不去支持滑动响应,最终通过在scrollViewDidScroll中根据滑动的控件做出对应的滚动偏移设置;
3、cell在点击时实现与系统TableView一样的高亮效果;