Giải pháp được đưa ra bởi @peerless là một khởi đầu tuyệt vời, nhưng nó chỉ khởi động một hình ảnh động mỗi khi bắt đầu kéo, mà không xem xét tốc độ của cuộn. Điều này dẫn đến trải nghiệm choppier hơn bạn nhận được trong ứng dụng Facebook. Để phù hợp với hành vi của Facebook, chúng tôi cần:
- ẩn / hiển thị thanh điều hướng ở tốc độ tỷ lệ thuận với tốc độ kéo
- khởi động một hình ảnh động để ẩn hoàn toàn thanh nếu cuộn dừng khi thanh bị ẩn một phần
- làm mờ dần các mục của thanh điều hướng khi thanh co lại.
Trước tiên, bạn sẽ cần các thuộc tính sau:
@property (nonatomic) CGFloat previousScrollViewYOffset;
Và đây là các UIScrollViewDelegate
phương pháp:
- (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];
}
}
Bạn cũng sẽ cần các phương thức trợ giúp này:
- (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];
}];
}
Đối với một hành vi hơi khác, thay thế dòng định vị lại thanh khi cuộn ( else
khối trong scrollViewDidScroll
) bằng hành vi này:
frame.origin.y = MIN(20,
MAX(-size, frame.origin.y -
(frame.size.height * (scrollDiff / scrollHeight))));
Điều này định vị thanh dựa trên tỷ lệ phần trăm cuộn cuối cùng, thay vì số lượng tuyệt đối, dẫn đến độ mờ chậm hơn. Hành vi ban đầu giống Facebook hơn, nhưng tôi cũng thích cái này.
Lưu ý: Giải pháp này chỉ dành cho iOS 7+. Hãy chắc chắn để thêm các kiểm tra cần thiết nếu bạn đang hỗ trợ các phiên bản iOS cũ hơn.