一、菜单栏 , 使用的组件是 YNPageScrollMenuView 。
二、UITableView数组
一、首先菜单栏是隐藏的,当tableview滑动到第一个基本信息分区头时显示出来,以后滑动到具体的分区头时,菜单栏定位到具体的对应位置 二、点击菜单栏上的按钮 ,tableview滑动到指定分区位置。bash
// 滚动到指定 NSIndexPath 处
一、- (void)scrollToRowAtIndexPath:(NSIndexPath *)indexPath atScrollPosition:(UITableViewScrollPosition)scrollPosition animated:(BOOL)animated;
// 滚动到指定的偏移位置处
二、- (void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated;
复制代码
获取到每一个 分区头 的位置,经过 setContentOffset 设置偏移量来让tableView滚动到具体位置。网络
那么咱们如何得到 每一个 分区头 的位置呢 ?post
一、 首先咱们经过网络请求获取到数据,构造数据源分区数组。(此时咱们知道了咱们有几个分区,每一个分区有几个Rows。)动画
二、核心:获取到每一个分区的Rect:遍历分区数据源分区数组,滚动到每一个分区的第一行,经过系统提供的 rectForSection 获取到每一个分区的Rect,将y值保存到一个数组里。ui
self.scrollYArr = [NSMutableArray array];
__block CGRect lastRect;
NSInteger sectioncounts = self.titleNameArr.count;
[self.titleNameArr enumerateObjectsUsingBlock:^(NSArray *sectionArr, NSUInteger index, BOOL * _Nonnull stop) {
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:index];
[self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:(UITableViewScrollPositionBottom) animated:NO];
CGRect section_all_Rect = [self.tableView rectForSection:index];
HTLog(@"section_all_Rect:%@",NSStringFromCGRect(section_all_Rect));
NSInteger currentPostion = (NSInteger)section_all_Rect.origin.y;
// 注意: 还需 减去 被 MenuView 遮挡的 Height 高度
currentPostion -= self.menuView.height;
[self.scrollYArr addObject:[NSNumber numberWithInteger:currentPostion]];
if (index == sectioncounts - 1) {
// 记录最后一个分区的位置
lastRect = section_all_Rect;
}
}];
复制代码
三、 设置表尾,若是不设置表尾,咱们是没法将最后一个分区或者几个分区滚动到屏幕最上方。因此咱们须要设置一个表尾。spa
CGFloat delt = self.tableView.height - lastRect.size.height - self.menuView.height;
UIView *newFootView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, HT_SCREEN_WIDTH, delt)];
self.tableView.tableFooterView = newFootView;
[self.tableView setContentOffset:CGPointMake(0, 0) animated:NO];
复制代码
四、到目前为止,咱们获取到每一个分区的具体的位置信息了,那么点击菜单栏按钮,滚动到对应分区就很好实现了。在菜单栏按钮的点击的代理方法中:代理
- (void)pagescrollMenuViewItemOnClick:(UIButton *)label index:(NSInteger)index{
if (index > self.titleNameArr.count - 1) {
return;
}
NSInteger currentPostion = [self.scrollYArr[index] integerValue];
[self.tableView setContentOffset:CGPointMake(0, currentPostion) animated:YES];
}
复制代码
五、而后就是滚动UITableView时获取偏移量,滑动到具体分区Rect的y值时,设置菜单栏滚动到指定按钮处。核心就是 UIScrollView 的几个代理方法的处理。code
#pragma mark - UIScrollViewDelegate
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
// 只要contentOffset变化,都会被调用(包括用户拖动,减速过程,直接经过代码设置等
if (scrollView.isTracking) {
HTLog(@"---手指拖动中-------- calculateScrollView");
[self calculateScrollView:scrollView];
}else{
if(scrollView.isDecelerating){
HTLog(@"---无手指减速滚动中--------calculateScrollView");
[self calculateScrollView:scrollView];
}
}
}
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{
// 用户开始拖动 scroll view 的时候被调用 可能须要一些时间和距离移动以后才会触发。
HTLog(@"1.将要开始拖动--------")
self.menuView.userInteractionEnabled = NO;
// 这边关闭菜单栏交互,是避免用户在拖拽后手指离开屏幕,此时TableView滚动中,用户再去点击菜单栏。这样是会影响tableview滑动以及菜单栏定位的。
}
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset{
/*
在 didEndDragging 前被调用,当 willEndDragging 方法中 velocity 为 CGPointZero
(结束拖动时两个方向都没有速度)时,didEndDragging 中的 decelerate 为 NO,即没有减速过程,
*/
HTLog(@"2.将要结束拖动--------");
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{
// 判断是否有减速过程
if (decelerate) {
HTLog(@"3.已经结束拖动--------有减速过程,无需处理,交给减速的代理方法处理");
}else{
HTLog(@"3.已经结束拖动--------没有有减速过程 calculateScrollView");
[self calculateScrollView:scrollView];
self.menuView.userInteractionEnabled = YES;
}
}
- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView{
// 减速动画开始前被调用。
HTLog(@"4.将要开始减速--------");
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
HTLog(@"5.已经结束减速--------calculateScrollView");
[self calculateScrollView:scrollView];
self.menuView.userInteractionEnabled = YES;
}
复制代码
六、处理偏移量,定位到具体哪一个菜单栏按钮cdn
- (void)calculateScrollView:(UIScrollView *)scrollView{
self.menuView.userInteractionEnabled = NO;
NSInteger currentPostion = (NSInteger)scrollView.contentOffset.y;
NSInteger count = self.scrollYArr.count;
__block NSInteger index = self.menuView.currentIndex;
[self.scrollYArr enumerateObjectsUsingBlock:^(NSNumber * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
NSInteger scrollY = [obj integerValue];
if (currentPostion < scrollY) {
index = idx - 1;
*stop = YES;
}else{
if (idx == count - 1) {
index = count - 1;
*stop = YES;
}
}
}];
index = MAX(0, index);
[self.menuView selectedItemIndex:index animated:YES];
// 处理隐藏效果
if(currentPostion >= [[self.scrollYArr firstObject] integerValue]){
if(self.menuView.alpha == 0){
[UIView animateWithDuration:0.1 animations:^{
self.menuView.alpha = 1;
} completion:nil];
}
}else{
self.menuView.alpha = 0;
}
}
复制代码