一、菜單欄 , 使用的組件是 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;
}
}
複製代碼