關(guān)于Android 4.4后所謂"沉浸式"效果的實(shí)現(xiàn)

某音樂播放器

寫在前面

  • 如圖某音樂播放器,這個(gè)效果就是所謂的"沉浸式"效果捏题。
  • Android與ios效果互仿早已不是什么稀奇的事玻褪,我猜大概這個(gè)效果來自ios吧,講真的公荧,這體驗(yàn)感覺真不錯(cuò)噢带射。
  • 有爭議說這種效果不能叫做沉浸式,叫透明狀態(tài)欄更合適循狰,我也感覺這和沉浸式的含義不太一致庸诱。
  • 但是大家都這么叫了,那就這樣唄晤揣。

原理

  • 從4.4后系統(tǒng)增加了透明狀態(tài)欄的特性WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
    一旦添加上這個(gè)屬性后,那么布局中的內(nèi)容DecorView就會(huì)自動(dòng)填充到狀態(tài)欄朱灿。所有的實(shí)現(xiàn)都是基于這個(gè)特性昧识,就相當(dāng)于這個(gè)時(shí)候狀態(tài)欄會(huì)默認(rèn)空出來,然后開發(fā)者可以自定義view來填充這個(gè)高度的.
  • 實(shí)現(xiàn)的過程中可能還要用到android:fitsSystemWindows="true",這個(gè)屬性很重要盗扒。
    其含義:view可以根據(jù)系統(tǒng)窗口(如status bar跪楞,軟鍵盤)來調(diào)整自己的布局缀去,如果值為true,就會(huì)調(diào)整view的paingding屬性來給system windows留出空間....

那么現(xiàn)在來看看具體實(shí)現(xiàn)方式吧

一般頁面都是自己定義個(gè)類標(biāo)題欄

實(shí)現(xiàn)

從實(shí)現(xiàn)效果上,這里大致分為兩種

單獨(dú)給狀態(tài)欄著色

  • 使用這個(gè)開源庫SystemBarTint

      /**
       * 狀態(tài)欄顏色設(shè)置方法
       * @param context
       * @param color
       */
      public static void smartTintManager(Activity context, int color){
          if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
              Window window = context.getWindow();
              window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
              // 創(chuàng)建狀態(tài)欄的管理實(shí)例
              SystemBarTintManager tintManager = new SystemBarTintManager(context);
              // 激活狀態(tài)欄設(shè)置
              tintManager.setStatusBarTintEnabled(true);
              tintManager.setStatusBarTintColor(color);
          }
      }
    
    1. 在對應(yīng)的頁面的根布局中添加android:fitsSystemWindows="true",且根布局中不能設(shè)置整體的大背景色甸祭,否則狀態(tài)欄著色就會(huì)被覆蓋
    2. 調(diào)用上面方法設(shè)置具體的顏色(依據(jù)開源庫缕碎,其中就一個(gè)核心類,可以直接把那個(gè)類拷貝到項(xiàng)目中)
  • 這里主要講一下具體的實(shí)現(xiàn)原理

      private void setupStatusBarView(Context context, ViewGroup decorViewGroup) {
          mStatusBarTintView = new View(context);
          LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, mConfig.getStatusBarHeight());
          params.gravity = Gravity.TOP;
          if (mNavBarAvailable && !mConfig.isNavigationAtBottom()) {
              params.rightMargin = mConfig.getNavigationBarWidth();
          }
          mStatusBarTintView.setLayoutParams(params);
          mStatusBarTintView.setBackgroundColor(DEFAULT_TINT_COLOR);
          mStatusBarTintView.setVisibility(View.GONE);
          decorViewGroup.addView(mStatusBarTintView);
      }
    

    通讀這段代碼池户,很容易看出咏雌,通過動(dòng)態(tài)生成一個(gè)view,然后這個(gè)view寬是MATCH_PARENT,高度是系統(tǒng)狀態(tài)欄的高度校焦;然后為這個(gè)動(dòng)態(tài)生成的view設(shè)置一個(gè)背景顏色赊抖;最后將這個(gè)view添加到decorViewGroup這個(gè)view容器中,那再看看這個(gè)view到底是誰

      /**
       * Constructor. Call this in the host activity onCreate method after its
       * content view has been set. You should always create new instances when
       * the host activity is recreated.
       *
       * @param activity The host activity.
       */
      @TargetApi(19)
      public SystemBarTintManager(Activity activity) {
    
          Window win = activity.getWindow();
          //獲得DecorView根布局容器
          ViewGroup decorViewGroup = (ViewGroup) win.getDecorView();  
          .....  
          if (mStatusBarAvailable) {
              // 這個(gè)view容器是decorViewGroup
              setupStatusBarView(activity, decorViewGroup);
          }
          if (mNavBarAvailable) {
              setupNavBarView(activity, decorViewGroup);
          }
    
      }
    

    注意看上面兩個(gè)我手動(dòng)添加的注釋寨典,可見氛雪,這種做法思想就是
    狀態(tài)欄透明后,向根布局decorViewGroup中添加一個(gè)和狀態(tài)欄等高度的view腾它。至于你讓這個(gè)view是什么顏色呻纹,那就隨你心情了缀踪。

用標(biāo)題欄的背景色來填充狀態(tài)欄

將狀態(tài)欄設(shè)置為半透明的,此時(shí)出現(xiàn)的問題是下面的內(nèi)容會(huì)占據(jù)了狀態(tài)欄弦追。
如果我們在activity的根布局添加 android:fitsSystemWindows="true"
那么此時(shí)狀態(tài)欄還是可以看見的,并沒有占據(jù)毙沾。那這個(gè)屬性的作用就在此了骗卜。

此時(shí)我們借助狀態(tài)欄的高度,為下面的內(nèi)容設(shè)置一個(gè)padding-top距離(因?yàn)闋顟B(tài)欄半透明后左胞,
下面的內(nèi)容會(huì)占據(jù)原有的狀態(tài)欄寇仓,那么將其設(shè)置一個(gè)padding的狀態(tài)欄高度即可)
這樣設(shè)置后,在這個(gè)view的背景的padding下烤宙,原有的狀態(tài)欄高度填充了同樣的背景色遍烦,那么這樣的話就貌似所謂的沉浸式了

這種方式說白了,就是狀態(tài)欄半透明后躺枕,用下面的內(nèi)容來合適的填充(因?yàn)槟J(rèn)半透明會(huì)是被占據(jù))
代碼如下:

@SuppressLint("InlinedApi")
public static void setImmerseLayout(Activity context, View view) {
    if (context == null || view == null) {
        return;
    }
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        Window window = context.getWindow();
        window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS,
                WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
        int statusBarHeight = getStatusBarHeight(context.getBaseContext());
        view.setPadding(0, statusBarHeight, 0, 0);
    }
}

/**
 * 用于獲取狀態(tài)欄的高度服猪。 使用Resource對象獲取(推薦這種方式)
 *
 * @return 返回狀態(tài)欄高度的像素值拐云。
 */
public static int getStatusBarHeight(Context context) {
    int result = 0;
    int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
    if (resourceId > 0) {
        result = context.getResources().getDimensionPixelSize(resourceId);
    }
    return result;
}
  • 對這個(gè)view設(shè)置一個(gè)padding_top罢猪,而這個(gè)padding的距離剛好是狀態(tài)欄的高度,那么這個(gè)view的背景就填充到了狀態(tài)欄了叉瘩。

  • 值得注意的是:這個(gè)標(biāo)題欄的高度一定要是wrap_content,因?yàn)槿绻蔷唧w的高度膳帕,然后在設(shè)置個(gè)paddingtop的話,那么就會(huì)把部分標(biāo)題欄的內(nèi)容擠出去了薇缅,不完整了危彩。

  • 所以通常的做法是將原有的標(biāo)題欄外面在嵌套一個(gè)<FrameLayout />攒磨,然后將標(biāo)題欄背景設(shè)置成<FrameLayout />的背景色

      <FrameLayout
          android:id="@+id/title"
          android:layout_width="match_parent"
          android:background="@color/common_theme_color"
          android:layout_height="wrap_content">
    

后記

關(guān)于沉浸式效果的實(shí)現(xiàn)方式就啰嗦這么多了.
另外,關(guān)于EditText及全屏Dialog等實(shí)現(xiàn)沉浸式問題汤徽,后期在更新娩缰,其實(shí)就是那個(gè)android:fitsSystemWindows="true"的靈活設(shè)置。歡迎交流谒府。

下一篇會(huì)實(shí)現(xiàn)一個(gè)效果:頁面頂部是圖片,滑動(dòng)漸變標(biāo)題欄

滑動(dòng)漸變2.gif
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末拼坎,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子狱掂,更是在濱河造成了極大的恐慌演痒,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,542評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件趋惨,死亡現(xiàn)場離奇詭異鸟顺,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)器虾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,596評論 3 385
  • 文/潘曉璐 我一進(jìn)店門讯嫂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人兆沙,你說我怎么就攤上這事欧芽。” “怎么了葛圃?”我有些...
    開封第一講書人閱讀 158,021評論 0 348
  • 文/不壞的土叔 我叫張陵千扔,是天一觀的道長。 經(jīng)常有香客問我库正,道長曲楚,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,682評論 1 284
  • 正文 為了忘掉前任褥符,我火速辦了婚禮龙誊,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘喷楣。我一直安慰自己趟大,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,792評論 6 386
  • 文/花漫 我一把揭開白布铣焊。 她就那樣靜靜地躺著逊朽,像睡著了一般。 火紅的嫁衣襯著肌膚如雪曲伊。 梳的紋絲不亂的頭發(fā)上惋耙,一...
    開封第一講書人閱讀 49,985評論 1 291
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼绽榛。 笑死,一個(gè)胖子當(dāng)著我的面吹牛婿屹,可吹牛的內(nèi)容都是我干的灭美。 我是一名探鬼主播,決...
    沈念sama閱讀 39,107評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼昂利,長吁一口氣:“原來是場噩夢啊……” “哼届腐!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起蜂奸,我...
    開封第一講書人閱讀 37,845評論 0 268
  • 序言:老撾萬榮一對情侶失蹤犁苏,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后扩所,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體围详,經(jīng)...
    沈念sama閱讀 44,299評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,612評論 2 327
  • 正文 我和宋清朗相戀三年祖屏,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了助赞。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,747評論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡袁勺,死狀恐怖雹食,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情期丰,我是刑警寧澤群叶,帶...
    沈念sama閱讀 34,441評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站钝荡,受9級特大地震影響街立,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜化撕,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,072評論 3 317
  • 文/蒙蒙 一几晤、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧植阴,春花似錦蟹瘾、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,828評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至喷鸽,卻和暖如春众雷,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,069評論 1 267
  • 我被黑心中介騙來泰國打工砾省, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留鸡岗,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,545評論 2 362
  • 正文 我出身青樓编兄,卻偏偏與公主長得像轩性,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子狠鸳,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,658評論 2 350

推薦閱讀更多精彩內(nèi)容