1. 程式人生 > >仿知乎主頁,上滑隱藏NavigationBar,下滑顯示

仿知乎主頁,上滑隱藏NavigationBar,下滑顯示

最近在仿作知乎客戶端,知乎首頁的 navigationBar 會隨著下方的 tableView 滑動而改變,上滑隱藏,下拉顯示,並且下拉需要一定速度才會觸發顯示。在網上查了一下,看到一個隨 TableView 滑動改變 NavigationBar 透明度的demo,雖然和自己的需求不一樣,但提供了利用 KVO 實現的思路,有了思路就著手做了,除錯了幾次和知乎官方實現效果稍有不同,但基本需求實現了,如果需要做到完全相同,只要再加一些條件判斷就好了,主要程式碼如下:

#import "TestTableViewController.h"

@interface TestTableViewController ()

@end

@implementation TestTableViewController {
    BOOL _isHidding;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self setupScrollHideNavigationBar];
    
    self.navigationItem.title = @"TEST DEMO";
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return 50;
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
    if (!cell) {
        cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cell"];
    }
    cell.textLabel.text = [NSString stringWithFormat:@"%d",(int)indexPath.row];
    
    return cell;
}

#pragma mark - 上拉隱藏navigation bar
- (void)setupScrollHideNavigationBar {
    //    self.tableView.contentOffset
    [self.tableView addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:nil];
}

- (void)removeScrollHideNavigationBar {
    //remove
    [self.tableView removeObserver:self forKeyPath:@"contentOffset"];
}
#pragma mark KVO
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
    if ([object isEqual:self.tableView] && [keyPath isEqualToString:@"contentOffset"]) {
        
        CGFloat newY = [change[@"new"] CGPointValue].y;
        CGFloat oldY = [change[@"old"] CGPointValue].y;
        float i = newY - oldY;       //i>0上滑, i<0下滑
        if (self.tableView.contentOffset.y>-64&&self.tableView.contentOffset.y<=24) {//邊界條件,此處不精確
            if (i<=0&&_isHidding == NO&&self.navigationController.navigationBar.frame.origin.y==20) {    //下拉+bar 已經顯示的狀態,不再移動
                return;
            }
            _isHidding = NO;
            self.navigationController.navigationBar.frame = CGRectMake(0, -44-self.tableView.contentOffset.y, 320, 44);
        }else if (self.tableView.contentOffset.y > 24) {
            
            if (i>10) {//更改數值大小可以控制觸發 navigation bar 的滑動速度
                _isHidding = YES;
            }else if(i<-10) {
                _isHidding = NO;
            }else {
                
            }
        }
        [self.navigationController setNavigationBarHidden:_isHidding animated:YES];
    }
}

程式碼很簡單就不詳解了,附上各種情況的判斷(上滑指手指上滑):


最終效果只在一種情況和知乎客戶端不一樣,就是上圖左下角的情況。


最終效果:


其他:NavigationController 需要 push/pop ViewController 的時候注意需要取消KVO,否則在其他介面可能會出現 NavigationBar 隱藏的情況。

參考: