iOS NavigationBar滑動時(shí)自動隱藏

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)位置偏移。

遞歸獲取_UINavigationBarContentViewsubviews,再更改其alpha,因?qū)Ш綐?biāo)題無法更改alpha,便采用了修改titleTextAttributesNSForegroundColorAttributeNamealpha來實(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。謝謝~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容