写在前面
首先声明哈,不是广告,我就是用的时候觉得这个功能比较好玩,就想着实现了一下。效果如图:
接下来简单的说一下思路吧~
大体思路
可能我们看到这种功能的实现的时候,首先想着的是我在这个控制器中左右各放一个tableView
,然后进行关联。我是用了另一个思路,具体如下:
我建了两个类LGJCategoryVC
用来盛放左边写着第几类的tableView和LGJProductsVC
用来盛放右边写在各种产品的tableView
。然后将LGJProductsVC
作为LGJCategoryVC
的childViewController,将LGJProductsVC
的view
addSubView到LGJCategoryVC
的view
上。
代码实现如下:
1
2
3
4
5
6
7
|
-
(
void
)
createProductsVC
{
_productsVC
=
[
[
LGJProductsVC
alloc
]
init
]
;
_productsVC
.
delegate
=
self
;
[
self
addChildViewController
:
_productsVC
]
;
[
self
.
view
addSubview
:
_productsVC
.
view
]
;
}
|
这样做有什么好处呢?简单的说就是将tableView
分离,各自使用一个congtroller
,这样做使每个控制器管理自己的tableView
里面的事件,可以更好的分离代码,降低两个tableView
之间的耦合度,同时也避免了把两个 tableView
放在一个controller
里造成一个controller
代码的冗余,这样使逻辑更清晰。
接下来说一下我们点击左边tableView
的cell
的时候怎样使右边的tableView
跟着滑动。我在LGJCategoryVC
也就是左边tableView
的这个代理方法中didSelectRowAtIndexPath
做了些操作:
1
2
3
4
5
6
|
-
(
void
)
tableView
:
(
UITableView
*
)
tableView
didSelectRowAtIndexPath
:
(
NSIndexPath
*
)
indexPath
{
if
(
_productsVC
)
{
[
_productsVC
scrollToSelectedIndexPath
:indexPath
]
;
}
}
|
其中这个scrollToSelectedIndexPath
方法是在_productsVC
中声明的。这个方法就是具体调动右边tableView
滑动的。
1
2
3
4
5
|
#pragma mark - 一级tableView滚动时 实现当前类tableView的联动
-
(
void
)
scrollToSelectedIndexPath
:
(
NSIndexPath
*
)
indexPath
{
[
self
.
productsTableView
selectRowAtIndexPath
:
(
[
NSIndexPath
indexPathForRow
:
0
inSection
:indexPath
.
row
]
)
animated
:YES
scrollPosition
:UITableViewScrollPositionTop
]
;
}
|
我们需要的只是让右边tableView
的sectionHeaderView
跟随左边的点击cell
移动到最上部就可以了,所以在这里我们设置selectRowAtIndexPath:([NSIndexPath indexPathForRow:0 inSection:indexPath.row])
接下来就是当我们滑动右边tableView
的时候左边的tableView
的cell
跟随滑动。这里我们在LGJProductsVC
类中声明了一个协议。
1
2
3
4
5
6
|
@protocol
ProductsDelegate
<NSObject>
-
(
void
)
willDisplayHeaderView
:
(
NSInteger
)
section
;
-
(
void
)
didEndDisplayingHeaderView
:
(
NSInteger
)
section
;
@end
|
同时声明两个变量,这两个变量非常有用。
1
2
|
@property
(
nonatomic
,
assign
)
BOOL
isScrollUp
;
//是否是向上滚动
@property
(
nonatomic
,
assign
)
CGFloat
lastOffsetY
;
//滚动即将结束时scrollView的偏移量
|
具体作用就在这里了:
1
2
3
4
5
6
7
8
|
#pragma mark - scrollViewDelegate
-
(
void
)
scrollViewDidScroll
:
(
UIScrollView
*
)
scrollView
{
NSLog
(
@"_lastOffsetY : %f,scrollView.contentOffset.y : %f"
,
_lastOffsetY
,
scrollView
.
contentOffset
.
y
)
;
_isScrollUp
=
_lastOffsetY
<
scrollView
.
contentOffset
.
y
;
_lastOffsetY
=
scrollView
.
contentOffset
.
y
;
NSLog
(
@"______lastOffsetY: %f"
,
_lastOffsetY
)
;
}
|
在这个方法中,_isScrollUp
用来判断右边的tableView
是否是向上滑,当scrollView
滑动时,我们用上次的偏移量和本次的偏移量作对比,如果上次的偏移量小于本次的偏移量说明tableView
是向上滑动的。(关于contentOffset我在上篇的《iOS 实现NavigationController的titleView动态缩放效果》链接:http://www.jianshu.com/p/bcf3d692f99d 中有简单介绍)此时,_isScrollUp
为YES,反之为NO。我们根据_isScrollUp
这个重要的标识来到这儿:UITableViewDelegate
的这两个代理方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
-
(
void
)
tableView
:
(
UITableView
*
)
tableView
willDisplayHeaderView
:
(
UIView
*
)
view
forSection
:
(
NSInteger
)
section
{
if
(
self
.
delegate
!=
nil
&&
[
self
.
delegate
respondsToSelector
:
@selector
(
willDisplayHeaderView
:
)
]
!=
_isScrollUp
)
{
[
self
.
delegate
willDisplayHeaderView
:section
]
;
}
}
-
(
void
)
tableView
:
(
UITableView
*
)
tableView
didEndDisplayingHeaderView
:
(
UIView
*
)
view
forSection
:
(
NSInteger
)
section
{
if
(
self
.
delegate
!=
nil
&&
[
self
.
delegate
respondsToSelector
:
@selector
(
didEndDisplayingHeaderView
:
)
]
&&
_isScrollUp
)
{
[
self
.
delegate
didEndDisplayingHeaderView
:section
]
;
}
}
|
在UITableViewDelegate
的这两个代理方法中,第一个方法是当headerView
将要显示时调用。第二个方法是当headerView
结束显示时调用。在这里我们根据_isScrollUp
的BOOL值,当headerView
将要显示的时候说明此时_isScrollUp
为NO,因为此时是向下滑动的。当headerView
结束显示的时候说明此时_isScrollUp
为YES,因为此时是向上滑动的。此时我们调用ProductsDelegate
代理方法,在LGJCategoryVC
类中实现代理方法:
1
2
3
4
5
6
7
8
9
10
|
#pragma mark - ProductsDelegate
-
(
void
)
willDisplayHeaderView
:
(
NSInteger
)
section
{
[
self
.
categoryTableView
selectRowAtIndexPath
:
[
NSIndexPath
indexPathForRow
:section
inSection
:
0
]
animated
:YES
scrollPosition
:UITableViewScrollPositionMiddle
]
;
}
-
(
void
)
didEndDisplayingHeaderView
:
(
NSInteger
)
section
{
[
self
.
categoryTableView
selectRowAtIndexPath
:
[
NSIndexPath
indexPathForRow
:section
+
1
inSection
:
0
]
animated
:YES
scrollPosition
:UITableViewScrollPositionMiddle
]
;
}
|
在willDisplayHeaderView
这个代理方法中,右边tableView
向下滑动,此时headerView
即将显示,左边cell
选择indexPathForRow:section
,在didEndDisplayingHeaderView
代理方法中,右边tableView
向上滑动,此时headerView
结束显示,左边cell
选择indexPathForRow:section+1
总结
基本的大体思路就是上面这些,可能老是左边tableView
右边tableView
的看起来有点儿绕了,具体的还是看代码吧。最后贴上代码链接:
https://github.com/iOSJason/TableViewTwoLevelLinkageDemo.git