iOS 關於navigationBar的一些:毛玻璃、透明、動態縮放、動態隱藏

原文出處: 霖溦(@羽霖溦 )php

前言html

本文整理了一些關於navigationBar的很是規的可是較爲實用的操做,包括利用毛玻璃、動態透明、動態item顏色、動態隱藏,以及頭視圖的動態縮放,並同時涉及了statusBar的動態設置(換色)。ios

先預覽下總體效果:git

Demo詳見GitHub:Demo_AboutNavigationBar
爲了便於展現,類沒有複用,也沒有繼承共有的父類,全部存在大量「有絲分裂」的重複代碼。。。說白了就是懶。。。千萬別學我就是了。github

1.不要「浪費」了這塊毛玻璃

這裏所謂的不要浪費,只是我的的偏好,固然也是順遂了蘋果的UI特點之一:毛玻璃穿透效果。web

通常界面上是有兩塊毛玻璃的:navigationBar和tabBar,不少APP都會自定義這兩塊Bar,不只是顏色,甚至是控件自己。單考慮利用系統的Bar的話,若是不自定義顏色,就是利用毛玻璃效果自己了,然而不少APP,也並未利用起這個毛玻璃效果,簡書的就是這樣,不過簡書應該是自定義了navigationBar?或許。編程

(這裏插一句,就是QQ的某次更新,更新以後,navigationBar的藍色變成了毛玻璃,以後的一次更新又換了回來……多是被吐槽太多?這裏應該是用戶習慣先入爲主的問題了;還有就是微信,微信應該算得上是個十分純粹的iOS風格的APP,有留意過的話,也會發現其navigationBar是黑色的毛玻璃,或許是barStyle = UIBarStyleBlack,由於微信也是有不少非原生的處理的。)瀏覽器

下面結合tableView介紹下其與navigationBar的毛玻璃的做用效果。知道我可能要囉嗦什麼的朋友可自行跳過這部份內容。微信

先對比下這兩種效果(圖不太清晰,仔細看navigationBar,仍是很容易對比出來差異的):架構


有毛玻璃穿透效果的效果


沒有毛玻璃穿透效果

1.1.通常的處理

 

 

1

2

3

4

5

6

7

8

9

10

11

  - (UITableView *)tableView

  {

      if (!_tableView) {

          _tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 64, ScreenWidth, ScreenHeight - 64)];

          _tableView.delegate = self;

          _tableView.dataSource = self;

          _tableView.backgroundColor = [UIColor whiteColor];

          _tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine;

      }

      return _tableView;

  }

相信有不少人大概是以與這樣相似的方式去初始化tableView的,origin.y=64,總高度-64,都是爲了防止navigationBar的遮擋,然而這樣的處理會產生一個bug,就是tableView總體竟然下移了64……,而後就有了這段解決代碼:

 

 

1

2

3

  if ([self respondsToSelector:@selector(automaticallyAdjustsScrollViewInsets)]) {

      self.automaticallyAdjustsScrollViewInsets = NO;

  }

這是iOS7的特性之一,navigationBar自適應scrollView滑動視圖,然而由於咱們的+64的處理,致使系統的這個默認開啓的功能就成了自做多情。若是

 

 

1

_tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, ScreenWidth, ScreenHeight)];

這樣作,以前的「bug」天然就會沒有,並且咱們想要的毛玻璃效果就會天然的展示出來(如上圖一),可是由於系統的自適應,在某些特殊狀況下,依舊會產生不可控的bug,因此剛纔處理bug的代碼,仍是有必要的。

1.2.「釋放」系統的毛玻璃效果的處理

配合:

 

 

1

2

3

  if ([self respondsToSelector:@selector(automaticallyAdjustsScrollViewInsets)]) {

      self.automaticallyAdjustsScrollViewInsets = NO;

  }

這樣初始化tableView:

 

 

1

2

3

4

5

6

7

8

9

10

11

12

13

  - (UITableView *)tableView

  {

      if (!_tableView) {

          _tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, ScreenWidth, ScreenHeight)];

          _tableView.delegate = self;

          _tableView.dataSource = self;

          _tableView.backgroundColor = [UIColor whiteColor];

          _tableView.contentInset = UIEdgeInsetsMake(64, 0, 0, 0);

          _tableView.scrollIndicatorInsets = UIEdgeInsetsMake(64, 0, 0, 0);

          _tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine;

      }

      return _tableView;

  }

這裏利用了edgeInset內嵌邊距,tableView的frame依舊是全屏尺寸的,只是設置了下contentInset使得其內容視圖的尺寸改變了,scrollIndicatorInsets是右側的滑動指示器,要跟着一塊兒才天然。若是當前頁還有tabBar的話,只須要設置UIEdgeInsetsMakebottom值就行。這樣,上圖一的毛玻璃穿透效果就天然的釋放了出來。

1.3.設置contentInset帶來的小問題

  • 1.webView初始加載時底部的黑條
    若是使用上述方式初始化webView(一樣是滑動視圖,有scrollView屬性,可設置scrollView.contentInset),至於所謂的「黑條」,大體相似於下面的效果:
    黑條出如今視圖底部,通常高度爲64,也就是contentInsettop值,上圖的由於設置關係要大不少。相信不少人都在瀏覽APP的webView時,在web加載完以前的空白頁時,見到過這一現象。

    關於這以現象的解決方法網上也有不少,我通常是在初始化時,將contentOffset.y設置一個(-64)的偏移量,這樣,初始進入webView時,在不滑動頁面的狀況下,是不可見的,這算是較爲溫和的解決方法吧,還有一種就是,初始化時設置opaque=NO,也就是使得view透明,可是在加載以後,要設置opaque=YES,也就是默認不透明,這樣,黑條是完全不可見的。

  • 2.滑動偏移量改變
    在實現一些滑動視圖的動態變化的處理中,例如稍後提到的動態縮放,通常會用代理檢測contentOffset.y值,可是由於設置了contentInset.top,此時contentOffset.y值也就發生了變化:

     

     

    1

    2

    3

    4

    - (void)scrollViewDidScroll:(UIScrollView *)scrollView

    {

        CGFloat offsetY = scrollView.contentOffset.y + self.tableView.contentInset.top;//注意

    }

    初始再也不是0,而是-64,也就是-top

1.4.爲何須要毛玻璃效果

費了一些功夫,都只是爲了實現毛玻璃效果,至於爲何要這個毛玻璃穿透效果,我也說很差,喜愛也罷,設計風格也罷,至少,感受這樣作出的APP,不用專門考慮各類Bar的配色什麼的,動態模糊穿透的彩色,也的確很漂亮,至少,iOS的UI風格有這樣的趨勢。也不要小瞧這個毛玻璃效果,真正實現一個高效的毛玻璃,也就是動態模糊渲染,也是很麻煩的,一些三方庫,爲了版本適配(適配iOS7),自定義的毛玻璃,也是利用了系統的toolBar。看過一些文章,介紹來介紹去,仍是說,用系統在iOS8以後提供的API實現毛玻璃是最好的方式。

下圖(渣圖……)是我最近封裝了有一陣子的一個自定義控件,一樣是爲了效果,用toolBar自定義了一塊毛玻璃,這個控件還未完全完善,稍後會開源,下圖只是其中一種樣式,這個控件的自定義程度仍是很是高的。

2.navigationBar的透明

有時候,咱們須要將navigationBar設置透明,但不是隱藏,由於還須要其item控件(返回鍵什麼的),雖然navigationBar是繼承於UIView的,可是直接設置其alpha是無效的,應該是由於navigationBar複合的視圖層級:


根據視圖層級關係,咱們用這個十分簡單的方法來設置navigationBar的透明:

 

 

1

[[[self.navigationController.navigationBar subviews] objectAtIndex:0] setAlpha:0];

關於navigationBar設置透明的方法,不知上述一種,還有許多,詳見此文,很是具備參考價值:

怎麼把頂部這個navigationbar設置爲透明呢,可以讓下面的圖片顯示出來,可是返回按鈕不透明?

若是想像QQ空間或者微博那樣動態的改變透明度,只須要在scrollViewDidScroll方法中,動態去設置alpha值就行,什麼時候開始改變、變化率全憑自定義的參數控制,具體詳見Demo中的代碼。

3.動態statusBar顏色

改變item的顏色很簡單,只需設置:

 

 

1

self.navigationController.navigationBar.tintColor = [UIColor blackColor];

動態設置的方式同剛纔的alpha。這裏主要說的是statusBar的顏色或者說樣式的改變。

iOS7以後,statusBar再也不是全局屬性,每一個VC均可自行控制statusBar的樣式,雖然樣式只有簡單的字體黑或白兩種,可是在不少狀況下都是頗有用的,尤爲是上面的navigationBar的alpha動態改變,在QQ空間中就有這個效果。
在設置statusBar樣式以前,須要作一個處理,並且是針對navigationBar的處理,在使用了navigationController以後,直接設置某一個VC的statusBar的樣式是無效的,由於navigationBar是惟一的,全部壓棧推出的VC,都是navigationController的子控制器,這就須要指定statusBar樣式改變的VC爲當前的topVC,具體方式網上也有不少,這裏只介紹我的使用的一種。

首先建立一個繼承於UINavigationController的子類,在這個類中實現下面的方法:

 

 

1

2

3

4

  - (UIViewController *)childViewControllerForStatusBarStyle

  {

      return self.topViewController;

  }

或者是一樣效果的這個方法:

 

 

1

2

3

4

5

  - (UIStatusBarStyle)preferredStatusBarStyle

  {

      UIViewController * topVC = self.topViewController;

      return [topVC preferredStatusBarStyle];

  }

以後,只需在要改變statusBar樣式的VC類中實現:

 

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

  #ifdef __IPHONE_7_0

  - (UIStatusBarStyle)preferredStatusBarStyle

  {

      if (_statusBarStyleControl) {

          return UIStatusBarStyleDefault;

      }

      else {

          return UIStatusBarStyleLightContent;

      }

  }

  - (BOOL)prefersStatusBarHidden

  {

      return NO;

  }

  #endif

__IPHONE_7_0是系統的宏,這裏用來版本適配,這個不寫貌似沒有關係?由於以前試了iOS7如下的系統沒有崩潰,iOS7以前沒有這個方法,應該是不會執行的,也就不會崩潰。

preferredStatusBarStyle就是控制用來控制statusBar顏色或者說樣式的,_statusBarStyleControl是自定義的一個用來動態控制的BOOL屬性。

prefersStatusBarHidden這個控制statusBar的顯示隱藏,建議NO或直接默認不寫,若是設置隱藏,視圖會總體上移20,效果不太好,看具體需求。

至於控制statusBar的改變,也是在scrollViewDidScroll代理中動態實現,例如某一狀況下觸發以下:

 

 

1

2

3

4

_statusBarStyleControl = YES;

if ([self respondsToSelector:@selector(setNeedsStatusBarAppearanceUpdate)]) {

    [self setNeedsStatusBarAppearanceUpdate];

}

第一步是設置以前提到的_statusBarStyleControl標誌位的值的切換,第二部是最重要的setNeedsStatusBarAppearanceUpdate,這個系統的方法是在改變statusBar顯示樣式以前必須執行的,不然preferredStatusBarStyle不會再當前視圖加載完成後再次執行。

4.navigationBar的動態隱藏

navigationBar的隱藏很簡單:

 

 

1

[self.navigationController setNavigationBarHidden:YES animated:YES];

這個方法可使動態隱藏時有動畫效果,不會顯得突兀。

動態隱藏的效果有兩個場景:一個就是例如簡書這樣的,在瀏覽時,上滑,navigationBar隱藏,下滑navigationBar顯示,在這期間,手指是不鬆開的,這須要實時檢測當前是上滑仍是下滑;第二個場景是Safari瀏覽器那樣的,滑動後鬆手,根據上滑仍是下滑設置隱藏(Safari的navigationBar不是隱藏,只是變化)。這樣的兩種場景雖然很類似,但就是鬆不鬆手的問題,處理方式和體驗也是徹底不一樣的。

  • 1.第二場景,鬆手
    這個處理十分簡單:

     

     

    1

    2

    3

    4

    5

    6

    7

    8

    9

    - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset{

        NSLog(@"======== %lf", velocity.y);

        if(velocity.y > 0) {

            [self.navigationController setNavigationBarHidden:YES animated:YES];

        }

        else {

            [self.navigationController setNavigationBarHidden:NO animated:YES];

        }

    }

    velocity.y這個量,在上滑和下滑時,變化極小(小數),可是由於方向不一樣,有正負之分,這就很好處理了。

  • 2.第一場景,不鬆手

     

     

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    - (void)scrollViewDidScroll:(UIScrollView *)scrollView

    {

        CGFloat offsetY = scrollView.contentOffset.y + _tableView.contentInset.top;//注意

        CGFloat panTranslationY = [scrollView.panGestureRecognizer translationInView:self.tableView].y;

     

        if (offsetY > 64) {

            if (panTranslationY > 0) { //下滑趨勢,顯示

                [self.navigationController setNavigationBarHidden:NO animated:YES];

            }

            else {  //上滑趨勢,隱藏

                [self.navigationController setNavigationBarHidden:YES animated:YES];

            }

        }

        else {

            [self.navigationController setNavigationBarHidden:NO animated:YES];

        }

    }

這裏的offsetY > 64只是爲了在視圖滑過navigationBar的高度以後纔開始處理,防止影響展現效果。

panTranslationY是scrollView的pan手勢的手指位置的y值,這個方法是我的本身想到的,可能不是太好,由於panTranslationY這個值在較小幅度上下滑動時,可能都爲正或都爲負,這就使得這一方式不太靈敏,若是有更好的方法,歡迎留言交流。

5.動態縮放

這個效果純粹是爲了仿簡書的我的信息的頭像的縮放效果。

頭像視圖的佈局直接利用了navigationBar的titleView,代碼仍是很好理解的,視圖層級關係以下:

頭像的一半是「懸空」的。

縮放只是滑動代理監聽時的一個動態縮放的過程,縮放率同以前說的alpha的動態變化同樣,自行設置常量,這裏注意縮放過程的分段執行,爲了效果,這個有下拉放大回彈的效果,這部分不是簡書的效果:

 

 

1

_topImageView.transform = CGAffineTransformMakeScale(1 - offsetY/300, 1 - offsetY/300);

若是隻是設置縮放,效果以下:

爲了使縮放過程當中位置相對保持,以前想到了改變錨點的方式,然而效果不好,最終仍是以簡單的方式實現:

 

 

1

2

3

CGRect frame = _topImageView.frame;

frame.origin.y = 5;

_topImageView.frame = frame;

就是保持y的座標爲初始值。

下面的這個仿微博的效果,也是基於一樣的原理,只是要注意圖層關係,詳細參考代碼,再也不贅述。

6.側滑返回

這算是個比較大的話題了,前面提到的那篇文章中有關於此的詳細論述,這裏只是簡單說起,稍後有機會,會專門寫一篇關於側滑返回的自定義實現。

iOS7以後,navigationController推出的視圖,只要返回按鈕不自定義覆蓋,或者相關屬性默認,右滑屏幕左邊緣,能夠直接pop返回,這是個十分方便的功能。關於實現和自定義實現,網上也有太多的文章。這裏只是說明一點,就是在設置navigationBar透明以後,使用側滑返回的過程當中,navigationBar會忽然出現,顯得十分突兀,這也是目前微博APP的效果,QQ和微信都針對此作了不一樣的處理,本文的Demo中也嘗試作了必定的處理,可是效果並非十分理想的,就是中斷側滑返回動做時,navigationBar閃的問題。這個問題已經超出本文內容的範圍,有機會會在從此的文章中介紹。

參考文章:
1.iOS開發的一些奇巧淫技
2.自定義iOS7導航欄背景,標題和返回按鈕文字顏色
3.Removing the title text of an iOS 7 UIBarButtonItem
4.iOS 實現ScrollView 上滑隱藏Navigationbar,下滑顯示
5.iOS 7 改變 app 的外觀(NavigationBar,TabBar,StatusBar)
6.iOS不一樣版本適配問題(#ifdef __IPHONE_7_0)
7. __IPHONE_OS_VERSION_MIN_REQUIRED
8.IOS開發之不一樣版本適配問題3(#ifdef __IPHONE_7_0 BaseSDK Development Target)
9.IOS開發之不一樣版本適配問題2(#ifdef __IPHONE_7_0)
10.ios7 statusBar的字體顏色怎麼設置爲白色的呢
11.IOS上 關於狀態欄的相關設置(UIStatusBar)
12.IOS7怎麼修改Navigation Bar上的返回按鈕文本顏色,箭頭顏色以及導航欄按鈕的顏色
13.怎麼把頂部這個navigationbar設置爲透明呢,可以讓下面的圖片顯示出來,可是返回按鈕不透明?
14.iOS navigationbar全透明的方法
15.IOS中設置UINavigationBar的各類樣式(圖片/透明效果/下方內容顯示狀況)
16.iOS開發UI篇—CAlayer層的屬性
17.iOS – UINavigationController簡介

問啊-定製化IT教育平臺,牛人一對一服務,有問必答,開發編程社交頭條 官方網站:www.wenaaa.com 下載問啊APP,參與官方懸賞,賺百元現金。


QQ羣290551701 彙集不少互聯網精英,技術總監,架構師,項目經理!開源技術研究,歡迎業內人士,大牛及新手有志於從事IT行業人員進入!

http://cxy.liuzhihengseo.com/477.html

相關文章
相關標籤/搜索