La soluzione fornita da @peerless è un ottimo inizio, ma dà il via a un'animazione ogni volta che inizia il trascinamento, senza considerare la velocità dello scorrimento. Ciò si traduce in un'esperienza più incisiva di quella che si ottiene nell'app Facebook. Per abbinare il comportamento di Facebook, dobbiamo:
- nasconde / mostra la barra di navigazione a una velocità proporzionale alla velocità di trascinamento
- dare il via a un'animazione per nascondere completamente la barra se lo scorrimento si interrompe quando la barra è parzialmente nascosta
- sbiadiscono gli oggetti della barra di navigazione mentre la barra si restringe.
Innanzitutto, avrai bisogno della seguente proprietà:
@property (nonatomic) CGFloat previousScrollViewYOffset;
E qui ci sono i UIScrollViewDelegate
metodi:
- (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];
}
}
Avrai anche bisogno di questi metodi di supporto:
- (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];
}];
}
Per un comportamento leggermente diverso, sostituire la linea che riposiziona la barra durante lo scorrimento (il else
blocco in scrollViewDidScroll
) con questo:
frame.origin.y = MIN(20,
MAX(-size, frame.origin.y -
(frame.size.height * (scrollDiff / scrollHeight))));
Ciò posiziona la barra in base all'ultima percentuale di scorrimento, anziché a un valore assoluto, con una dissolvenza più lenta. Il comportamento originale è più simile a Facebook, ma mi piace anche questo.
Nota: questa soluzione è solo per iOS 7+. Assicurati di aggiungere i controlli necessari se stai supportando le versioni precedenti di iOS.