it-swarm.com.ru

Подражать Facebook скрывать/показывать расширение/сжатие Панель навигации

В новом приложении iOS7 для iPhone на Facebook, когда пользователь прокручивает вверх, navigationBar постепенно скрывается до точки, где он полностью исчезает. Затем, когда пользователь прокручивает вниз, navigationBar постепенно показывает себя. 

Как бы вы реализовали это поведение самостоятельно? Мне известно следующее решение, но оно сразу исчезает, и оно вообще не связано со скоростью жеста прокрутки пользователя. 

[navigationController setNavigationBarHidden: YES animated:YES];

Я надеюсь, что это не дубликат, так как я не уверен, как лучше всего описать поведение "расширения/сжатия".

125
El Mocoso

Решение, данное @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];
    }];
}

Для немного другого поведения замените строку, которая перемещает панель при прокрутке (блок else в scrollViewDidScroll), следующим:

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

Это позиционирует полосу на основе последнего процента прокрутки, а не абсолютного значения, что приводит к более медленному затуханию. Исходное поведение больше похоже на Facebook, но мне оно тоже нравится.

Примечание. Это решение доступно только для iOS 7+. Не забудьте добавить необходимые проверки, если вы поддерживаете старые версии iOS.

161
Wayne Burkett

Правка: только для iOS 8 и выше.

Вы можете попробовать использовать 

self.navigationController.hidesBarsOnSwipe = YES;

Работает для меня.

Если ваша кодировка в Swift, вы должны использовать этот способ (с https://stackoverflow.com/a/27662702/2283308 )

navigationController?.hidesBarsOnSwipe = true
52
Pedro Romão

Вот еще одна реализация: TLYShyNavBar v1.0.0 выпущен!

Я решил сделать свое собственное решение после того, как попробовал предоставленные решения, и для меня они либо работали плохо, либо имели высокий барьер входа и код котельной плиты, либо не имели расширенного вида под панелью навигации. Чтобы использовать этот компонент, все, что вам нужно сделать, это:

self.shyNavBarManager.scrollView = self.scrollView;

О, и это боевое испытание в нашем собственном приложении.

43
Mazyod

Вы можете взглянуть на мой GTScrollNavigationBar . Я создал подкласс UINavigationBar для прокрутки на основе прокрутки UIScrollView.

Примечание. Если у вас есть панель навигации OPAQUE, вид прокрутки должен РАСШИРЯТЬСЯ, так как панель навигации скрыта. Это именно то, что делает GTScrollNavigationBar. (Так же, как, например, в Safari на iOS.)

33
Thuy

iOS8 содержит свойства, позволяющие скрыть панель навигации бесплатно. Есть видео WWDC, которое демонстрирует это, поиск "Просмотр достижений контроллера в iOS 8".

Пример:

class QuotesTableViewController: UITableViewController {

override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)

    navigationController?.hidesBarsOnSwipe = true
}

}

Другие свойства:

class UINavigationController : UIViewController {

    //... truncated

    /// When the keyboard appears, the navigation controller's navigationBar toolbar will be hidden. The bars will remain hidden when the keyboard dismisses, but a tap in the content area will show them.
    @availability(iOS, introduced=8.0)
    var hidesBarsWhenKeyboardAppears: Bool
    /// When the user swipes, the navigation controller's navigationBar & toolbar will be hidden (on a swipe up) or shown (on a swipe down). The toolbar only participates if it has items.
    @availability(iOS, introduced=8.0)
    var hidesBarsOnSwipe: Bool
    /// The gesture recognizer that triggers if the bars will hide or show due to a swipe. Do not change the delegate or attempt to replace this gesture by overriding this method.
    @availability(iOS, introduced=8.0)
    var barHideOnSwipeGestureRecognizer: UIPanGestureRecognizer { get }
    /// When the UINavigationController's vertical size class is compact, hide the UINavigationBar and UIToolbar. Unhandled taps in the regions that would normally be occupied by these bars will reveal the bars.
    @availability(iOS, introduced=8.0)
    var hidesBarsWhenVerticallyCompact: Bool
    /// When the user taps, the navigation controller's navigationBar & toolbar will be hidden or shown, depending on the hidden state of the navigationBar. The toolbar will only be shown if it has items to display.
    @availability(iOS, introduced=8.0)
    var hidesBarsOnTap: Bool
    /// The gesture recognizer used to recognize if the bars will hide or show due to a tap in content. Do not change the delegate or attempt to replace this gesture by overriding this method.
    @availability(iOS, introduced=8.0)
    unowned(unsafe) var barHideOnTapGestureRecognizer: UITapGestureRecognizer { get }
}

Найдено через http://natashatherobot.com/navigation-bar-interactions-ios8/

25
Michael Peterson

Это работает для iOS 8 и выше и гарантирует, что строка состояния все еще сохраняет свой фон

self.navigationController.hidesBarsOnSwipe = YES;
CGRect statuBarFrame = [UIApplication sharedApplication].statusBarFrame;
UIView *statusbarBg = [[UIView alloc] initWithFrame:statuBarFrame];
statusbarBg.backgroundColor = [UIColor blackColor];
[self.navigationController.view addSubview:statusbarBg];

И если вы хотите показать панель навигации при нажатии на строку состояния, вы можете сделать это:

- (void)scrollViewDidScrollToTop:(UIScrollView *)scrollView {
     self.navigationController.navigationBarHidden = NO;
}
12
Zhong Huiwen

У меня есть какое-то быстрое и грязное решение для этого. Не проводил всестороннего тестирования, но вот идея:

Это свойство будет хранить все элементы в панели навигации для моего класса UITableViewController.

@property (strong, nonatomic) NSArray *navBarItems;

В том же классе UITableViewController у меня есть:

-(void)scrollViewDidScrollToTop:(UIScrollView *)scrollView
{
    if([[[UIDevice currentDevice] systemVersion] floatValue] < 7.0f){
        return;
    }

    CGRect frame = self.navigationController.navigationBar.frame;
    frame.Origin.y = 20;

    if(self.navBarItems.count > 0){
        [self.navigationController.navigationBar setItems:self.navBarItems];
    }

    [self.navigationController.navigationBar setFrame:frame];
}

-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    if([[[UIDevice currentDevice] systemVersion] floatValue] < 7.0f){
        return;
    }

    CGRect frame = self.navigationController.navigationBar.frame;
    CGFloat size = frame.size.height - 21;

    if([scrollView.panGestureRecognizer translationInView:self.view].y < 0)
    {
        frame.Origin.y = -size;

        if(self.navigationController.navigationBar.items.count > 0){
            self.navBarItems = [self.navigationController.navigationBar.items copy];
            [self.navigationController.navigationBar setItems:nil];
        }
    }
    else if([scrollView.panGestureRecognizer translationInView:self.view].y > 0)
    {
        frame.Origin.y = 20;

        if(self.navBarItems.count > 0){
            [self.navigationController.navigationBar setItems:self.navBarItems];
        }
    }

    [UIView beginAnimations:@"toggleNavBar" context:nil];
    [UIView setAnimationDuration:0.2];
    [self.navigationController.navigationBar setFrame:frame];
    [UIView commitAnimations];
}

Это только для ios> = 7, это ужасно, я знаю, но быстрый способ достичь этого. Любые комментарии/предложения приветствуются :)

12
peerless

Вот моя реализация: SherginScrollableNavigationBar .

В моем подходе я использую KVO для наблюдения за состоянием UIScrollView, поэтому нет необходимости использовать делегата (и вы можете использовать этот делегат для всего, что вам нужно).

10
Valentin Shergin

Пожалуйста, попробуйте это мое решение и дайте мне знать, почему это не так хорошо, как предыдущие ответы.

- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
{
    if (fabs(velocity.y) > 1)
        [self hideTopBar:(velocity.y > 0)];
}

- (void)hideTopBar:(BOOL)hide
{
    [self.navigationController setNavigationBarHidden:hide animated:YES];
    [[UIApplication sharedApplication] setStatusBarHidden:hide withAnimation:UIStatusBarAnimationSlide];
}
7
Nishant

Один из способов, которым я достиг этого, заключается в следующем.

Зарегистрируйте ваш контроллер представления, чтобы быть, например, UIScrollViewDelegate вашего UITableView.

- (void)scrollViewDidScroll:(UIScrollView *)scrollView;
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView;
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate;

Из методов de UIScrollViewDelegate вы можете получить новый contentOffset и перевести ваш UINavigationBar соответственно вверх или вниз.

Настройка альфа-подпредставлений также может быть выполнена на основе некоторых пороговых значений и факторов, которые вы можете установить и вычислить.

Надеюсь, поможет!

6
Diana Sule

В дополнение к ответу Iwburk я добавил следующее, чтобы исправить проблему с альфой на нестандартных панелях навигации и сбросить панель навигации в методе viewWillDisappear:

- (void)updateBarButtonItems:(CGFloat)alpha
{
    for (UIView *view in self.navigationController.navigationBar.subviews) {
        NSString *className = NSStringFromClass([view class]);

        if ( ![className isEqualToString:@"_UINavigationBarBackground"] ) {
            view.alpha = alpha;
        }
    }
}

- (void)resetNavigationBar {
    CGRect frame = self.navigationController.navigationBar.frame;
    frame.Origin.y = 20;
    [self.navigationController.navigationBar setFrame:frame];
    [self updateBarButtonItems:1.0f];
}
4
blueice

Я искал решение, которое учитывало бы любой стиль и любое поведение. Вы заметите, что поведение конденсации полос отличается во многих разных приложениях. И, конечно же, внешний вид панели в разных приложениях совершенно другой. 

Я создал решение для этой проблемы с https://github.com/bryankeller/BLKF FlexibleHeightBar/

Вы можете определить свои собственные правила поведения, чтобы контролировать, как и когда полоса сжимается и растет, и вы можете точно определить, как вы хотите, чтобы подпредставления бара реагировали на уплотнение или рост бара.

Посмотрите на мой проект, если вам нужна большая гибкость, чтобы создать любую панель заголовков, которую вы можете придумать. 

4
blkhp19

HidingNavigationBar отличный проект, который скрывает панель навигации и панель вкладок, если хотите.

HidingNavigationBar поддерживает скрытие/отображение следующего представления элементы:

UINavigationBar

UINavigationBar и расширение UIView

UINavigationBar и UIToolbar

UINavigationBar и UITabBar

https://github.com/tristanhimmelman/HidingNavigationBar

3
Michael Peterson

Я пытался эмулировать это поведение в ситуации, когда мне нужен настраиваемый заголовок, сидящий около UITableView. Я свернул свою собственную панель «навигации», потому что она находится под кучей других вещей на странице, и я хотел, чтобы заголовки разделов следовали стандартному поведению «закрепления». Я думаю, что нашел довольно умный и лаконичный способ настроить UITableView/UIScrollView вместе с другим объектом в стиле, подобном тому, который видели в Facebook/Instagram/Chrome/и т.д. Программы. 

В моем файле .xib мои компоненты загружены в представление произвольной формы: http://imgur.com/0z9yebJ (извините, у меня нет представителя для встроенных изображений)

Обратите внимание, что в левой боковой панели таблица упорядочена за основным видом заголовка. Вы не можете сказать по скриншоту, но он также имеет ту же позицию y, что и основной вид заголовка. Поскольку он выходит за пределы поля зрения, свойство contentInset в UITableView установлено равным 76 (высота представления основного заголовка).

Чтобы основной вид заголовка скользил вверх в унисон с UIScrollView, я использую методы scrollViewDidScroll из UIScrollViewDelegate, чтобы выполнить некоторые вычисления и изменить contentInset UIScrollView, а также фрейм представления основного заголовка.

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    UIEdgeInsets insets = scrollView.contentInset;
    //tableViewInsetDelta and tableViewOriginalInsetValue are NSInteger variables that I set to 0 and 76, respectively, in viewDidLoad
    tableViewInsetDelta = tableViewOriginalInsetValue + scrollView.contentOffset.y;
    insets.top = tableViewOriginalInsetValue - tableViewInsetDelta;

    if (scrollView.contentOffset.y > -76 && scrollView.contentOffset.y < 0) {
        [scrollView setContentInset:insets];
        self.pathTitleContainer.frame = CGRectMake(self.pathTitleContainer.frame.Origin.x, 44 - tableViewInsetDelta, self.pathTitleContainer.frame.size.width, self.pathTitleContainer.frame.size.height);
    } else if (scrollView.contentOffset.y > 0) {
        insets.top = 0;
        [scrollView setContentInset:insets];
        self.pathTitleContainer.frame = CGRectMake(self.pathTitleContainer.frame.Origin.x, -32, self.pathTitleContainer.frame.size.width, self.pathTitleContainer.frame.size.height);
    } else if (scrollView.contentOffset.y < -76) {
        insets.top = 76;
        [scrollView setContentInset:insets];
        self.pathTitleContainer.frame = CGRectMake(self.pathTitleContainer.frame.Origin.x, 44, self.pathTitleContainer.frame.size.width, self.pathTitleContainer.frame.size.height);
    }
}

Первая инструкция if выполняет большую часть тяжелой работы, но мне пришлось включить две другие для обработки ситуаций, когда пользователь перетаскивает принудительно, а начальные значения contentOffset, отправленные в scrollViewDidScroll, находятся вне диапазона первого оператор if

В конечном счете, это работает очень хорошо для меня. Я ненавижу загружать свои проекты кучей раздутых подклассов. Я не могу сказать, является ли это лучшим решением с точки зрения производительности (я всегда колебался ставить какой-либо код в scrollViewDidScroll, так как он вызывается все время), но занимаемая площадь кода - наименьшая, которую я видел в любой Решение для этой проблемы, и оно не включает в себя вложение UITableView в UIScrollView (Apple рекомендует против этого в документации, и сенсорные события заканчиваются немного фанки на UITableView). Надеюсь, это поможет кому-то!

3
Brian

Я пытался реализовать GTScrollNavigationBar, но мое приложение требовало от меня изменения ограничений автоматического макета. Я решил выложить пример своей реализации на GitHub на тот случай, если кому-то еще придется делать это с автоматической разметкой. Другая проблема, с которой я столкнулся в большинстве других реализаций, заключается в том, что люди не устанавливают границы представления прокрутки, чтобы избежать эффекта прокрутки параллакса, который вы создаете во время прокрутки и одновременно регулируете размер прокрутки.

Проверьте JSCollapsingNavBarViewController , если вам нужно сделать это с автоматической разметкой. Я включил две версии, одна с только панелью навигации, а другая с суббаром под панелью навигации, которая сворачивается перед свертыванием панели навигации.

2
jwswart

я попробовал это таким образом, я надеюсь, что это поможет . просто реализовать код в методе делегата и установить на желаемое представление/подпредставление

-(void)scrollViewDidScroll:(UIScrollView *)scrollView{ 
            CGRect frame=self.view.frame;
            CGRect resultFrame=CGRectZero;
            if(scrollView.contentOffset.y==0 || scrollView.contentOffset.y<0){
                self.lastContentOffset=0;
                self.offset=0;
                resultFrame=CGRectMake(0, frame.size.height-(40-self.offset.intValue), frame.size.width, 40-self.offset.intValue);
    // Pass the resultFrame
                [self showHide:YES withFrame:resultFrame];
            }else if (self.lastContentOffset > scrollView.contentOffset.y){
                NSNumber *temp=[NSNumber numberWithDouble:self.lastContentOffset-scrollView.contentOffset.y];
                if(temp.intValue>40 || self.offset.intValue<temp.intValue){
                    self.offset=[NSNumber numberWithInt:0];
                    resultFrame=CGRectMake(0, frame.size.height-(40-self.offset.intValue), frame.size.width, 40-self.offset.intValue);
    // Pass the resultFrame
                    [self showHide:YES withFrame:resultFrame];
                }else{
                    if(temp.intValue>0){
                        self.offset=[NSNumber numberWithInt:self.offset.intValue-temp.intValue];
                        resultFrame=CGRectMake(0, frame.size.height-(40-self.offset.intValue), frame.size.width, 40-self.offset.intValue);
    // Pass the resultFrame
                        [self showHide:YES withFrame:resultFrame];
                    }
                }
            }else if (self.lastContentOffset < scrollView.contentOffset.y){
                NSNumber *temp=[NSNumber numberWithDouble:scrollView.contentOffset.y-self.lastContentOffset];
                if(self.offset.intValue>40 || (self.offset.intValue+temp.intValue)>40){
                    self.offset=[NSNumber numberWithInt:40];
    // Pass the resultFrame
                    [self showHide:NO withFrame:resultFrame];
                }else{
                    self.offset=[NSNumber numberWithInt:self.offset.intValue+temp.intValue];
                    resultFrame=CGRectMake(0, frame.size.height-(40-self.offset.intValue), frame.size.width, 40-self.offset.intValue);
    // Pass the resultFrame
                    [self showHide:YES withFrame:resultFrame];
                }
            }
            self.lastContentOffset = scrollView.contentOffset.y;

        }

-(void)showHide:(Boolean)boolView withFrame:(CGRect)frame{
               if(showSRPFilter){
                        //Assign value of "frame"to any view on which you wan to to perform animation
                }else{
                       //Assign value of "frame"to any view on which you wan to to perform animation
                }
        }
1
user2968901

Расширение ответа @Iwburk ... Вместо того, чтобы менять Происхождение навигационной панели, мне нужно было увеличить/уменьшить размер навигационной панели.

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    CGRect frame = self.previousRect; // a property set in the init method to hold the initial size of the uinavigationbar
    CGFloat size = frame.size.height;
    CGFloat framePercentageHidden = ((MINIMUMNAVBARHEIGHT - 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 = -MINIMUMNAVBARHEIGHT;
    } else if ((scrollOffset + scrollHeight) >= scrollContentSizeHeight) {
        frame.Origin.y = -size;
    } else {
        frame.Origin.y = MIN(-MINIMUMNAVBARHEIGHT, MAX(-size, frame.Origin.y - scrollDiff));
    }

    self.previousRect = CGRectMake(0, frame.Origin.y, self.jsExtendedBarView.frame.size.width, 155);
    self.layoutConstraintExtendedViewHeight.constant = MAXIMUMNAVBARHEIGHT + frame.Origin.y + MINIMUMNAVBARHEIGHT;
    [self updateBarButtonItems:(1 - framePercentageHidden)];
    self.previousScrollViewYOffset = scrollOffset;
}

Он пока не работает с методом stoppedScrolling, постараюсь опубликовать обновление, когда оно у меня будет

1
jsetting32

Все эти подходы кажутся чрезмерно сложными ... Поэтому, естественно, я создал свой собственный:

class ViewController: UIViewController, UIScrollViewDelegate {
    var originalNavbarHeight:CGFloat = 0.0
    var minimumNavbarHeight:CGFloat = 0
    weak var scrollView:UIScrollView!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        // setup delegates 
        scrollView.delegate = self
        // save the original nav bar height
        originalNavbarHeight = navigationController!.navigationBar.height
    }


    func scrollViewDidScroll(scrollView: UIScrollView) {
        // will relayout subviews
        view.setNeedsLayout() // calls viewDidLayoutSubviews
    }

    override func viewDidLayoutSubviews() {
        var percentageScrolled = min(scrollView.contentOffset.y / originalNavbarHeight, 1)
        navigationController?.navigationBar.height = min(max((1 - percentageScrolled) * originalNavbarHeight, minimumNavbarHeight), originalNavbarHeight)
        // re-position and scale scrollview
        scrollView.y = navigationController!.navigationBar.height + UIApplication.sharedApplication().statusBarFrame.height
        scrollView.height = view.height - scrollView.y
    }

    override func viewWillDisappear(animated: Bool) {
        navigationController?.navigationBar.height = originalNavbarHeight
    }

}
0
Oxcug

Я нашел все ответы, данные в Objective-C. Это мой ответ в Swift 3. Это очень общий код, который можно использовать напрямую. Он работает как с UIScrollView, так и с UITableView.

var lastContentOffset: CGPoint? = nil
var maxMinus: CGFloat           = -24.0
var maxPlus: CGFloat            = 20.0
var initial: CGFloat            = 0.0

override func viewDidLoad() {
    super.viewDidLoad()

    self.title = "Alarm Details"
    self.lastContentOffset = self.alarmDetailsTableView.contentOffset
    initial = maxPlus
}

func scrollViewDidScroll(_ scrollView: UIScrollView)
{
    var navigationBarFrame: CGRect   = self.navigationController!.navigationBar.frame
    let currentOffset = scrollView.contentOffset

    if (currentOffset.y > (self.lastContentOffset?.y)!) {
        if currentOffset.y > 0 {
            initial = initial - fabs(CGFloat(currentOffset.y - self.lastContentOffset!.y))
        }
        else if scrollView.contentSize.height < scrollView.frame.size.height {
            initial = initial + fabs(CGFloat(currentOffset.y - self.lastContentOffset!.y))
        }
    }
    else {
        if currentOffset.y < scrollView.contentSize.height - scrollView.frame.size.height {
            initial = initial + fabs(CGFloat(currentOffset.y - self.lastContentOffset!.y))
        }
        else if scrollView.contentSize.height < scrollView.frame.size.height && initial < maxPlus {
            initial = initial - fabs(CGFloat(currentOffset.y - self.lastContentOffset!.y))
        }
    }

    initial = (initial <= maxMinus) ? maxMinus : initial
    initial = (initial >= maxPlus) ? maxPlus : initial

    navigationBarFrame.Origin.y = initial

    self.navigationController!.navigationBar.frame = navigationBarFrame
    scrollView.frame = CGRect(x: 0.0, y: initial + navigationBarFrame.size.height , width: navigationBarFrame.size.width, height: self.view.frame.size.height - (initial + navigationBarFrame.size.height))

    let framePercentageHidden: CGFloat              = ((20 - navigationBarFrame.Origin.y) / (navigationBarFrame.size.height));
    self.lastContentOffset                          = currentOffset;
    self.updateBarButtonItems(alpha: 1 - framePercentageHidden)
}

func updateBarButtonItems(alpha: CGFloat)
{
    self.navigationController?.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName: UIColor.darkGray.withAlphaComponent(alpha)]
    self.navigationController?.navigationBar.isUserInteractionEnabled = (alpha < 1) ? false: true

    guard (self.navigationItem.leftBarButtonItems?.count) != nil else { return }

    for (_, value) in self.navigationItem.leftBarButtonItems!.enumerated() {
        value.customView?.alpha = alpha
    }

    guard (self.navigationItem.rightBarButtonItems?.count) != nil else { return }

    for (_, value) in (self.navigationItem.rightBarButtonItems?.enumerated())! {
        value.customView?.alpha = alpha
    }
}

Логика установки альфа для элементов навигации скопирована из @ WayneBurkett answer и переписана в Swift 3.

0
Dev