La solución dada por @peerless es un gran comienzo, pero solo inicia una animación cada vez que comienza el arrastre, sin considerar la velocidad del desplazamiento. Esto da como resultado una experiencia más agitada que la que obtienes en la aplicación de Facebook. Para que coincida con el comportamiento de Facebook, necesitamos:
- ocultar / mostrar la barra de navegación a una velocidad proporcional a la velocidad de arrastre
- inicie una animación para ocultar completamente la barra si el desplazamiento se detiene cuando la barra está parcialmente oculta
- desvanecen los elementos de la barra de navegación a medida que la barra se encoge.
Primero, necesitará la siguiente propiedad:
@property (nonatomic) CGFloat previousScrollViewYOffset;
Y aquí están los UIScrollViewDelegate
métodos:
- (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 métodos 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 reubica la barra al desplazarse (el else
bloque hacia adentro scrollViewDidScroll
) con esta:
frame.origin.y = MIN(20,
MAX(-size, frame.origin.y -
(frame.size.height * (scrollDiff / scrollHeight))));
Esto posiciona la barra en función 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 parecido a Facebook, pero también me gusta este.
Nota: Esta solución es solo para iOS 7+. Asegúrese de agregar las comprobaciones necesarias si admite versiones anteriores de iOS.