ios - 模仿Facebook隐藏/显示扩展/收缩导航栏

在新的 iOS7 Facebook iPhone 应用程序中,当用户向上滚动时,navigationBar 会逐渐将自身隐藏到完全消失的地步。然后当用户向下滚动 navigationBar 逐渐显示自己。

您将如何自己实现此行为?我知道以下解决方案,但它会立即消失,并且根本与用户滚动手势的速度无关。

[navigationController setNavigationBarHidden: YES animated:YES];

我希望这不是重复,因为我不确定如何最好地描述“扩展/收缩”行为。

最佳答案

@peerless 给出的解决方案是一个很好的开始,但它只在拖动开始时启动动画,而不考虑滚动的速度。这会导致比您在 Facebook 应用程序中获得的体验更不稳定。为了匹配 Facebook 的行为,我们需要:

  • 以与拖动速率成比例的速率隐藏/显示导航栏
  • 如果在栏部分隐藏时滚动停止,则启动动画以完全隐藏栏
  • 在导航栏缩小时淡化导航栏的项目。

首先,您需要以下属性:

@property (nonatomic) CGFloat previousScrollViewYOffset;

这里是 UIScrollViewDelegate 方法:

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    CGRect frame = self.navigationController.navigationBar.frame;
    CGFloat size = frame.size.height - 21;
    CGFloat framePercentageHidden = ((20 - frame.origin.y) / (frame.size.height - 1));
    CGFloat scrollOffset = scrollView.contentOffset.y;
    CGFloat scrollDiff = scrollOffset - self.previousScrollViewYOffset;
    CGFloat scrollHeight = scrollView.frame.size.height;
    CGFloat scrollContentSizeHeight = scrollView.contentSize.height + scrollView.contentInset.bottom;

    if (scrollOffset <= -scrollView.contentInset.top) {
        frame.origin.y = 20;
    } else if ((scrollOffset + scrollHeight) >= scrollContentSizeHeight) {
        frame.origin.y = -size;
    } else {
        frame.origin.y = MIN(20, MAX(-size, frame.origin.y - scrollDiff));
    }

    [self.navigationController.navigationBar setFrame:frame];
    [self updateBarButtonItems:(1 - framePercentageHidden)];
    self.previousScrollViewYOffset = scrollOffset;
}

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
    [self stoppedScrolling];
}

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView 
                  willDecelerate:(BOOL)decelerate
{
    if (!decelerate) {
        [self stoppedScrolling];
    }
}

您还需要这些辅助方法:

- (void)stoppedScrolling
{
    CGRect frame = self.navigationController.navigationBar.frame;
    if (frame.origin.y < 20) {
        [self animateNavBarTo:-(frame.size.height - 21)];
    }
}

- (void)updateBarButtonItems:(CGFloat)alpha
{
    [self.navigationItem.leftBarButtonItems enumerateObjectsUsingBlock:^(UIBarButtonItem* item, NSUInteger i, BOOL *stop) {
        item.customView.alpha = alpha;
    }];
    [self.navigationItem.rightBarButtonItems enumerateObjectsUsingBlock:^(UIBarButtonItem* item, NSUInteger i, BOOL *stop) {
        item.customView.alpha = alpha;
    }];
    self.navigationItem.titleView.alpha = alpha;
    self.navigationController.navigationBar.tintColor = [self.navigationController.navigationBar.tintColor colorWithAlphaComponent:alpha];
}

- (void)animateNavBarTo:(CGFloat)y
{
    [UIView animateWithDuration:0.2 animations:^{
        CGRect frame = self.navigationController.navigationBar.frame;
        CGFloat alpha = (frame.origin.y >= y ? 0 : 1);
        frame.origin.y = y;
        [self.navigationController.navigationBar setFrame:frame];
        [self updateBarButtonItems:alpha];
    }];
}

对于稍微不同的行为,将滚动时重新定位栏的行(scrollViewDidScroll 中的 else block )替换为以下行:

frame.origin.y = MIN(20, 
                     MAX(-size, frame.origin.y - 
                               (frame.size.height * (scrollDiff / scrollHeight))));

这会根据最后一个滚动百分比而不是绝对量来定位条,这会导致较慢的淡入淡出。最初的行为更像 Facebook,但我也喜欢这个。

注意:此解决方案仅适用于 iOS 7+。如果您支持旧版本的 iOS,请务必添加必要的检查。

https://stackoverflow.com/questions/19819165/

相关文章:

ios - iPhone/iPad的UILabel如何设置粗体和斜体?

ios - 更改 UITableView 部分标题的字体大小

ios - 在 iPhone App 中如何检测设备的屏幕分辨率

ios - 如何在 UIView 的顶部添加边框

iphone - 如何使用可选方法创建协议(protocol)?

objective-c - 是否可以在 Obj-C 中使用 Swift 的枚举?

iphone - iOS:如何执行 HTTP POST 请求?

objective-c - 错误 : writable atomic property cannot

objective-c - 在 Objective-C 中加入一个数组

ios - 不推荐使用旋转方法,相当于 'didRotateFromInterfaceOrienta