NavigationBar滑動時(shí)自動隱藏,和twitter的效果一樣。
向上滑動時(shí),將會隱藏NavigationBar,隱藏后可顯示更多的內(nèi)容。向下滑動時(shí),將會顯示導(dǎo)航欄。
最重要的是pod STNavigationBarAutoHide 后,你僅需一句代碼便可實(shí)現(xiàn)此功能。
[self st_navigationBarAutoHideConfigureScrollView:yourScrollView];
Demo效果
![]() |
![]() |
|---|
實(shí)現(xiàn)思路
滑動隱藏navigationBar分為兩部分,位置偏移及導(dǎo)航欄上內(nèi)容透明度調(diào)整。
通過修改navigationBar的transform.ty實(shí)現(xiàn)位置偏移。
遞歸獲取_UINavigationBarContentView的subviews,再更改其alpha,因?qū)Ш綐?biāo)題無法更改alpha,便采用了修改titleTextAttributes中NSForegroundColorAttributeName的alpha來實(shí)現(xiàn)透明度調(diào)整。
實(shí)現(xiàn)細(xì)節(jié)
記錄下開始拖動時(shí)的偏移量
- (void)st_scrollViewWillBeginDragging:(UIScrollView *)scrollView {
CGFloat contentOffsetY = scrollView.contentOffset.y + scrollView.adjustedContentInset.top;
[self st_setBeginContentOffsetY:contentOffsetY];
}
滑動時(shí),判斷是否隱藏
- (void)st_scrollViewDidScroll:(UIScrollView *)scrollView {
CGFloat contentOffsetY = scrollView.contentOffset.y + scrollView.adjustedContentInset.top;
//滑動距離,大于0時(shí),向上滑動;小于0時(shí),向下滑動。
CGFloat scrollOffsetY = contentOffsetY - [self st_beginContentOffsetY];
//導(dǎo)航欄高度
CGFloat navigationBarHeight = self.navigationController.navigationBar.frame.size.height;
//導(dǎo)航欄是否隱藏
bool navigationBarHidden = [self st_navigationBarHidden];
//向上滑動且導(dǎo)航未隱藏
if (scrollOffsetY > 0 && !navigationBarHidden) {
//滑動距離(下方用于計(jì)算動畫進(jìn)度)不大于導(dǎo)航高度
scrollOffsetY = MIN(navigationBarHeight, scrollOffsetY);
//滑動距離等于導(dǎo)航高度時(shí),導(dǎo)航欄完全隱藏
if (scrollOffsetY == navigationBarHeight) {
[self st_setNavigationBarHidden:true];
[self st_setBeginContentOffsetY:contentOffsetY];
}
//計(jì)算動畫進(jìn)度,更改導(dǎo)航內(nèi)容透明度
CGFloat alpha = (navigationBarHeight - scrollOffsetY) / navigationBarHeight;
[self updateNavigationBarAlpha:alpha];
//更改導(dǎo)航位置偏移量
self.navigationController.navigationBar.transform = CGAffineTransformMakeTranslation(0, -scrollOffsetY);
}
//向下滑動 并且 偏移量小于導(dǎo)航高度 并且 導(dǎo)航已隱藏時(shí),顯示導(dǎo)航
else if (scrollOffsetY < 0 && contentOffsetY < navigationBarHeight && navigationBarHidden) {
[self st_showNavigationBarWithAnimated:true];
}
}
拖動結(jié)束時(shí),判斷是否隱藏
- (void)st_scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset {
//速度
CGFloat velocityY = velocity.y;
//速度小于0時(shí),向下拖動,顯示導(dǎo)航欄
if (velocityY < 0) {
[self st_showNavigationBarWithAnimated:true];
}
//速度為0時(shí)
else if (velocityY == 0) {
CGFloat contentOffsetY = scrollView.contentOffset.y + scrollView.adjustedContentInset.top;
CGFloat scrollOffsetY = contentOffsetY - [self st_beginContentOffsetY];
CGFloat navigationBarHeight = self.navigationController.navigationBar.frame.size.height;
//偏移量小于導(dǎo)航高度時(shí),顯示導(dǎo)航欄
if (contentOffsetY < navigationBarHeight) {
[self st_showNavigationBarWithAnimated:true];
} else {
//導(dǎo)航當(dāng)前位置偏移
CGFloat transformTy = self.navigationController.navigationBar.transform.ty;
//當(dāng)導(dǎo)航已隱藏,或已顯示時(shí),return
if (transformTy == 0 && transformTy == -navigationBarHeight) return;
if (scrollOffsetY <= 0) return;
//處理向上拖動,導(dǎo)航未完全隱藏時(shí),拖動結(jié)束情況
if (transformTy >= -navigationBarHeight / 2.0) {
[self st_showNavigationBarWithAnimated:true];
} else {
[self st_hideNavigationBarWithAnimated:true];
}
}
}
}
用category封裝
新建UIViewController+NavigationBarAutoHide類
配置scrollView
- (void)st_navigationBarAutoHideConfigureScrollView:(UIScrollView *)scrollView {
if (scrollView == nil) {
NSLog(@"[ST NavigationBarAutoHide Error] scrollView cannot be nil!");
return;
}
if (self.navigationController == nil) {
NSLog(@"[ST NavigationBarAutoHide Error] self.navigationController cannot be nil!");
return;
}
if (scrollView.delegate == nil) {
scrollView.delegate = self;
}
//自動隱藏默認(rèn)設(shè)為可用
[self st_setNavigationBarAutoHideEnabled:true];
//交換scrollView delegate上方用到的三個(gè)方法
[self st_swizzleScrollViewDelegateMethod];
}
交換scrollView delegate用到的三個(gè)方法
- (void)st_swizzleScrollViewDelegateMethod {
[self st_swizzleScrollViewMethodWithOriginalSelector:@selector(scrollViewDidScroll:) swizzleSelector:@selector(st_scrollViewDidScroll:)];
[self st_swizzleScrollViewMethodWithOriginalSelector:@selector(scrollViewWillBeginDragging:) swizzleSelector:@selector(st_scrollViewWillBeginDragging:)];
[self st_swizzleScrollViewMethodWithOriginalSelector:@selector(scrollViewWillEndDragging:withVelocity:targetContentOffset:) swizzleSelector:@selector(st_scrollViewWillEndDragging:withVelocity:targetContentOffset:)];
}
- (void)st_swizzleScrollViewMethodWithOriginalSelector:(SEL)originalSelector swizzleSelector:(SEL)swizzleSelector {
Method originalMethod = class_getInstanceMethod([self class], originalSelector);
Method swizzledMethod = class_getInstanceMethod([self class], swizzleSelector);
//若未實(shí)現(xiàn)代理方法,則先添加代理方法
BOOL didAddOriginalMethod = st_addMethod([self class], originalSelector, originalMethod);
BOOL didAddSwizzledMethod = st_addMethod([self class], swizzleSelector, swizzledMethod);
if (didAddOriginalMethod) {
Method newOriginalMethod = class_getInstanceMethod([self class], originalSelector);
if (originalMethod == newOriginalMethod) {
didAddOriginalMethod = false;
}
}
if (didAddSwizzledMethod) {
Method newSwizzledMethod = class_getInstanceMethod([self class], swizzleSelector);
if (swizzledMethod == newSwizzledMethod) {
didAddSwizzledMethod = false;
}
}
//如果兩個(gè)方法都存在,則表示已交換過
if (!didAddOriginalMethod && !didAddSwizzledMethod) return;
st_swizzleSelector([self class], originalSelector, swizzleSelector);
}
static inline BOOL st_addMethod(Class theClass, SEL selector, Method method) {
return class_addMethod(theClass, selector, method_getImplementation(method), method_getTypeEncoding(method));
}
static inline void st_swizzleSelector(Class theClass, SEL originalSelector, SEL swizzledSelector) {
Method originalMethod = class_getInstanceMethod(theClass, originalSelector);
Method swizzledMethod = class_getInstanceMethod(theClass, swizzledSelector);
method_exchangeImplementations(originalMethod, swizzledMethod);
}
最后
更多細(xì)節(jié)可查看源碼,STNavigationBarAutoHide,支持pod。
如果你有問題,可以在github上給我提Issue或者在下方評論。
如果此項(xiàng)目有幫助到你,請給我一個(gè)star。謝謝~

