navigationbar在轉(zhuǎn)場(chǎng)切換時(shí)分別使用不同的背景色

類似文章挺多的,大家都說的非常好,我就是湊湊熱鬧......

應(yīng)用場(chǎng)景:

當(dāng)前界面的設(shè)置一個(gè)透明的navigationbar的背景,并且實(shí)現(xiàn)漸變顯示或隱藏的動(dòng)畫,二級(jí)界面的navigationbar的背景不透明,使用APP的主題背景色(例如:不透明且無毛玻璃效果);

實(shí)現(xiàn)效果:

demo480.gif

實(shí)現(xiàn)思路:

將系統(tǒng)原有導(dǎo)航欄的背景設(shè)置為透明色,同時(shí)在每個(gè) ViewController 上添加一個(gè) View 或者 NavigationBar 來充當(dāng)我們實(shí)際看到的導(dǎo)航欄,每個(gè) ViewController 同樣只需要關(guān)心自身的樣式即可。

第一步:增加一個(gè)屬性

用于記錄對(duì)navigationbar背景色的引用,用于實(shí)現(xiàn)navigationbar背景色變換動(dòng)畫;

/**
 記錄對(duì)navigationbar背景色的引用,用于實(shí)現(xiàn)背景色變換動(dòng)畫;
 */
@property (nonatomic, strong) UIView *navigationBarBgViewRef;

第二步:在viewDidLoad中加入代碼:

(1)打開navigationbar的背景毛玻璃效果;
(2)設(shè)置navigationbar的背景為一張透明圖片;
(3)在self.view中添加一張模擬出來的navigaionbar的背景圖片;

    /**
     不使用navigationbar自帶的背景顏色,
     而是使用自己模擬的navigationbar背景色
     */
    [self.navigationController.navigationBar setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];

self.navigationBarBgViewRef = [self appendSimulatorNavigationBarBgViewWithColor:COLOR_THEME];

第三步:在viewWillApear中加入代碼:

因?yàn)樵诒窘缑娴亩?jí)界面中可能會(huì)修改navigationbar的樣式,所以當(dāng)回到本界面時(shí),要恢復(fù)到本界面應(yīng)當(dāng)顯示的效果;
(1)打開navigationbar的背景毛玻璃效果;
(2)設(shè)置navigationbar的背景為一張透明圖片;

self.navigationController.navigationBar.translucent = YES;
[self.navigationController.navigationBar setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
self.navigationBarBgViewRef.alpha = 0;

補(bǔ)充相關(guān)代碼

#define WIDTH_SCREEN         [[UIScreen mainScreen] bounds].size.width      //屏幕寬度
#define HEIGHT_SCREEN        [[UIScreen mainScreen] bounds].size.height     //屏幕高度
#define IS_IPHONE_X (WIDTH_SCREEN == 375.f && HEIGHT_SCREEN == 812.f ? YES : NO)
#define IS_IPHONE_XSMAX (WIDTH_SCREEN == 414.f && HEIGHT_SCREEN == 896.f ? YES : NO)
#define HEIGHT_STATUSBAR    (IS_IPHONE_X || IS_IPHONE_XSMAX ? 44.f : 20.f)
#define HEIGHT_NAVIGATION_BAR   44

- (UIView *)appendSimulatorNavigationBarBgViewWithColor:(UIColor *)color {
    NSInteger simulatorBgViewTag = -9834534;//該值是胡亂定義的,就是個(gè)tag而已
    if([self.view viewWithTag:simulatorBgViewTag]){
        UIView *simulatorView = [self.view viewWithTag:simulatorBgViewTag];
        [simulatorView removeFromSuperview];
    }
    CGFloat height = HEIGHT_NAVIGATION_BAR + HEIGHT_STATUSBAR;
    CGSize size = CGSizeMake(WIDTH_SCREEN, height);
    UIImage *imgNavBg = [UIImage imageWithColor:color size:size];
    UIImageView *imgview = [[UIImageView alloc] initWithImage:imgNavBg];
    imgview.contentMode = UIViewContentModeScaleToFill;
    imgview.frame = CGRectMake(0, -1 * height, WIDTH_SCREEN,height);
    imgview.tag = simulatorBgViewTag;//胡亂輸入的
    [self.view addSubview:imgview];
    return imgview;
    
}


在界面切換時(shí),實(shí)現(xiàn)navigationbar轉(zhuǎn)場(chǎng)變換效果有三種方法,在美團(tuán)《iOS系統(tǒng)中導(dǎo)航欄的轉(zhuǎn)場(chǎng)解決方案與最佳實(shí)踐》中有很詳細(xì)的描述,這里僅摘抄部分,本文中提到的方案其實(shí)就是美團(tuán)這篇文章中說到的方案二,文章的鏈接如下:
https://tech.meituan.com/navigation_transition_solution_and_best_practice_in_meituan.html

常見的解決方案如下所示:【摘抄自美團(tuán)思琦《iOS系統(tǒng)中導(dǎo)航欄的轉(zhuǎn)場(chǎng)解決方案與最佳實(shí)踐》】

  1. 重新實(shí)現(xiàn)一個(gè)類似 UINavigationController 的容器類視圖管理器,這個(gè)容器類視圖管理器做好不同 ViewController 間的導(dǎo)航欄樣式轉(zhuǎn)換工作,而每個(gè) ViewController 只需要關(guān)心自身的樣式即可。

    19常見的導(dǎo)航欄轉(zhuǎn)場(chǎng)方案1示例圖
  2. 將系統(tǒng)原有導(dǎo)航欄的背景設(shè)置為透明色,同時(shí)在每個(gè) ViewController 上添加一個(gè) View 或者 NavigationBar 來充當(dāng)我們實(shí)際看到的導(dǎo)航欄,每個(gè) ViewController 同樣只需要關(guān)心自身的樣式即可。

    20常見的導(dǎo)航欄轉(zhuǎn)場(chǎng)方案2示例圖
  3. 在轉(zhuǎn)場(chǎng)的過程中隱藏原有的導(dǎo)航欄并添加假的 NavigationBar,當(dāng)轉(zhuǎn)場(chǎng)結(jié)束后刪除假的 NavigationBar 并恢復(fù)原有的導(dǎo)航欄,這一過程可以通過 Swizzle 的方式完成,而每個(gè) ViewController 只需要關(guān)心自身的樣式即可。

    21常見的導(dǎo)航欄轉(zhuǎn)場(chǎng)方案3示例圖

這三種方案各有優(yōu)劣,我們?cè)诰W(wǎng)上也可以看到很多關(guān)于它們的討論。

例如方案一,雖然看起來工作量大且難度高,但是這個(gè)工作一旦完成,我們就會(huì)將處理導(dǎo)航欄轉(zhuǎn)場(chǎng)的主動(dòng)權(quán)牢牢抓在手里。但這個(gè)方案的一個(gè)弊端就是,如果蘋果修改了導(dǎo)航欄的整體風(fēng)格,就好比 iOS 11 的大標(biāo)題特效,那么工作量就來了。

對(duì)于方案二而言,雖然看起來簡(jiǎn)單易用,但這需要一個(gè)良好的繼承關(guān)系,如果整個(gè)工程里的繼承關(guān)系混亂或者是歷史包袱比較重,后續(xù)的維護(hù)就像“打補(bǔ)丁”一樣,另外這個(gè)方案也需要良好的團(tuán)隊(duì)代碼規(guī)范和完善的技術(shù)文檔來做輔助。

對(duì)于方案三而言,它不需要所謂的繼承關(guān)系,使用起來也相對(duì)簡(jiǎn)單,這對(duì)于那些繼承關(guān)系和歷史包袱比較重的工程而言,這一個(gè)不錯(cuò)的解決方案,但在解決 Bug 的時(shí)候,Swizzle 這種方式無疑會(huì)增加解決問題的時(shí)間成本和學(xué)習(xí)成本。

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

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

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