Imite Facebook ocultar / mostrar expandir / contratar barra de navigation

En la nueva aplicación para iPhone Facebook iOS7, cuando el usuario se desplaza hacia arriba, la navigationBar se esconde gradualmente hasta desaparecer por completo. Luego, cuando el usuario se desplaza hacia abajo, la navigationBar se muestra gradualmente.

¿Cómo implementarías este comportamiento tú mismo? Soy consciente de la siguiente solución, pero desaparece de inmediato y no está ligada a la velocidad del gesto de desplazamiento del usuario.

 [navigationController setNavigationBarHidden: YES animated:YES]; 

Espero que esto no sea un duplicado, ya que no estoy seguro de la mejor manera de describir el comportamiento de "expansión / contratación".

La solución dada por @peerless es un gran comienzo, pero solo inicia una animation cada vez que comienza el arrastre, sin tener en count la velocidad del desplazamiento. Esto resulta en una experiencia choppier de la que obtienes en la aplicación de Facebook. Para que coincida con el comportamiento de Facebook, necesitamos:

  • ocultar / mostrar la barra de navigation a una velocidad proporcional a la velocidad de arrastre
  • inicia una animation para ocultar completamente la barra si el desplazamiento se detiene cuando la barra está parcialmente oculta
  • desvanezca los elementos de la barra de navigation cuando la barra se encoge.

Primero, necesitará la siguiente propiedad:

 @property (nonatomic) CGFloat previousScrollViewYOffset; 

Y aquí están los methods 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]; } } 

También necesitará estos methods de ayuda:

 - (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]; }]; } 

Para un comportamiento ligeramente diferente, reemplace la línea que reposiciona la barra al desplazarse (el bloque else en scrollViewDidScroll ) con esta:

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

Esto posiciona la barra en function del último porcentaje de desplazamiento, en lugar de una cantidad absoluta, lo que resulta en un desvanecimiento más lento. El comportamiento original es más similar a Facebook, pero a mí también me gusta.

Nota: esta solución solo tiene iOS 7+. Asegúrese de agregar las comprobaciones necesarias si está admitiendo versiones anteriores de iOS.

EDITAR: solo para iOS 8 y superior.

Puedes probar usar

 self.navigationController.hidesBarsOnSwipe = YES; 

Funciona para mi.

Si su encoding en swift tiene que usar esta forma (desde https://stackoverflow.com/a/27662702/2283308 )

 navigationController?.hidesBarsOnSwipe = true 

Aquí hay una implementación más: ¡ TLYShyNavBar v1.0.0 lanzado!

Decidí hacer el mío después de probar las soluciones provistas, y para mí, funcionaban mal, tenían una alta barrera de input y un código de placa de caldera, o carecían de la vista de extensión debajo de la barra de navigation. Para usar este componente, todo lo que tiene que hacer es:

 self.shyNavBarManager.scrollView = self.scrollView; 

Ah, y se testing la batalla en nuestra propia aplicación.

Puedes echar un vistazo a mi GTScrollNavigationBar . He subclassado UINavigationBar para que se desplace según el desplazamiento de un UIScrollView.

Nota: Si tiene una barra de navigation OPAQUE, la vista de desplazamiento debe EXPANDAR mientras la barra de navigation se OCULTAN. Esto es exactamente lo que hace GTScrollNavigationBar. (Al igual que en, por ejemplo, Safari en iOS).

iOS8 incluye properties para ocultar la barra de navigation de manera gratuita. Hay un video WWDC que lo demuestra, busca "Ver avances de controller en iOS 8".

Ejemplo :

 class QuotesTableViewController: UITableViewController { override func viewDidAppear(animated: Bool) { super.viewDidAppear(animated) navigationController?.hidesBarsOnSwipe = true } 

}

Otras properties:

 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 } } 

Encontrado a través de http://natashatherobot.com/navigation-bar-interactions-ios8/

Tengo una solución rápida y sucia para eso. No he hecho ninguna testing exhaustiva, pero aquí está la idea:

Esa propiedad mantendrá todos los elementos en la barra de navigation para mi class UITableViewController

 @property (strong, nonatomic) NSArray *navBarItems; 

En la misma class UITableViewController tengo:

 -(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]; } 

Eso es solo para ios> = 7, es feo, lo sé, pero es una forma rápida de lograr esto. Cualquier comentario / sugerencia son bienvenidos 🙂

Aquí está mi implementación: SherginScrollableNavigationBar .

En mi enfoque KVO para observar el estado de UIScrollView , así que no hay necesidad de usar un delegado (y puedes usar este delegado para cualquier otra cosa que necesites).

Esto funciona para iOS 8 y superior y garantiza que la barra de estado conserva su background

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

Y si desea mostrar la barra de navigation cuando toca la barra de estado, puede hacer esto:

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

Pruebe esta solución mía y déjeme saber por qué esto no es tan bueno como las respuestas anteriores.

 - (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 shanetworkingApplication] setStatusBarHidden:hide withAnimation:UIStatusBarAnimationSlide]; } 

Una de las forms en que he logrado esto es la siguiente.

Registre su controller de vista para que sea UIScrollViewDelegate de su UITableView por ejemplo.

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

Desde dentro de los methods UIScrollViewDelegate puede get el nuevo contenidoOffset y traducir su UINavigationBar hacia arriba o hacia abajo según corresponda.

La configuration del alfa de las subvistas también se puede hacer en function de algunos valores de umbral y factores que puede establecer y calcular.

¡Espero eso ayude!

Además de la respuesta de Iwburk, agregué lo siguiente para corregir el problema alfa en barras de navigation no personalizadas y para restablecer la barra de navigation en el método 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]; } 

Estaba buscando una solución que permitiera cualquier estilo y comportamiento. Notarás que el comportamiento de condensación de la barra es diferente en muchas aplicaciones diferentes. Y, por supuesto, la forma en que se ve la barra es totalmente diferente entre las aplicaciones.

Creé una solución para este problema con https://github.com/bryankeller/BLKFlexibleHeightBar/

Puede definir sus propias reglas de comportamiento para controlar cómo y cuándo la barra se contrae y crece, y puede definir exactamente cómo desea que las subvistas de la barra reaccionen a la barra que se está condensando o creciendo.

Echa un vistazo a mi proyecto si quieres mucha flexibilidad para hacer cualquier tipo de barra de encabezado que puedas pensar.

Intenté implementar GTScrollNavigationBar, pero mi aplicación me obligó a modificar las restricciones de layout automático. Decidí poner un ejemplo de mi implementación en GitHub en caso de que alguien más tenga que hacer esto con layout automático. El otro problema que tuve con la mayoría de las otras implementaciones es que las personas no establecen los límites de la vista de desplazamiento para evitar el efecto de desplazamiento de paralaje que se crea mientras se desplaza y ajusta el tamaño de la vista de desplazamiento al mismo time.

Eche un vistazo a JSCollapsingNavBarViewController si necesita hacer esto con layout automático. He incluido dos versiones, una con la barra de navigation solo y otra con una barra secundaria debajo de la barra de navigation que queuepsa antes de queuepsar la barra de navigation.

Estaba tratando de emular este comportamiento en una situación en la que necesitaba un encabezado personalizado sentado sobre una UITableView. Hice rodar mi propia barra de "navigation" porque esto se encuentra debajo de un montón de otras cosas en la página y quería que los encabezados de la sección siguieran el comportamiento pnetworkingeterminado de "acoplamiento". Creo que encontré una forma bastante inteligente y concisa de ajustar un UITableView / UIScrollView junto con otro object en un estilo similar al que se ve en Facebook / Instagram / Chrome / etc. aplicaciones

En mi file .xib, tengo mis componentes cargados en una vista de forma libre: http://imgur.com/0z9yebJ (lo siento, no tengo el rep para imágenes en línea)

Observe que, en la barra lateral izquierda, la tabla se ordera detrás de la vista del encabezado principal. No se puede saber de la captura de pantalla, pero también tiene la misma position que la vista del encabezado principal. Dado que se extiende fuera de la vista, la propiedad contentInset en UITableView se establece en 76 (la altura de la vista del encabezado principal).

Para hacer que la vista del encabezado principal se deslice al unísono con UIScrollView, utilizo los methods scrollViewDidScroll de UIScrollViewDelegate para realizar algunos cálculos y cambiar el contenido de UIScrollView, así como el marco de la vista del encabezado principal.

 - (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); } } 

La primera instrucción if hace la mayor parte del trabajo pesado, pero tuve que include los otros dos para manejar situaciones en las que el usuario está arrastrando con fuerza y ​​los valores iniciales del juego de contenido enviado a scrollViewDidScroll están fuera del range de la primera instrucción if .

En última instancia, esto está funcionando muy bien para mí. Odio cargar mis proyectos con un montón de subclasss hinchadas. No puedo hablar si esta es la mejor solución en cuanto al performance (siempre he dudado de poner ningún código en scrollViewDidScroll ya que se llama todo el time), pero la huella del código es la más pequeña que he visto en ninguna solución para este problema y no implica anidar un UITableView en un UIScrollView (Apple aconseja esto en la documentation y los events táctiles terminan un poco funky en el UITableView). Espero que esto ayude a alguien!

HidingNavigationBar un gran proyecto que oculta la barra de navigation y la barra de tabs si lo desea.

HidingNavigationBar admite esconder / mostrar los siguientes elementos de vista:

UINavigationBar

UINavigationBar y una extensión UIView

UINavigationBar y una barra UITool

UINavigationBar y un UITabBar

https://github.com/tristanhimmelman/HidingNavigationBar

Lo intenté de esta manera, espero que sea de ayuda. simplemente implemente el código en el método delegado y configúrelo en la vista / subvista deseada

 -(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 } } 

Una extensión de la respuesta de @Iwburk … En lugar de cambiar el origen de la barra de navigation, necesitaba expandir / networkingucir el tamaño de la barra de navigation.

 - (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; } 

No funciona con el método stoppedScrolling todavía, si stoppedScrolling una actualización cuando la tengo

Todos estos enfoques parecen excesivamente complicados … Así que, naturalmente, construí el mío:

 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.shanetworkingApplication().statusBarFrame.height scrollView.height = view.height - scrollView.y } override func viewWillDisappear(animated: Bool) { navigationController?.navigationBar.height = originalNavbarHeight } } 

Encontré todas las respuestas dadas en Objective-C. Esta es mi respuesta en Swift 3. Este es un código muy genérico y se puede usar directamente. Funciona tanto con UIScrollView como con 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 } } 

La lógica de establecer los elementos de alfa a navigation se copy de la respuesta @ WayneBurkett y se reescribe en Swift 3.