另外一种设置沉浸式标题栏的方式

今天又看到了另外一种设置沉浸式标题栏的方式,比上次写的那个使用主题,设置主题背景色的要好很多了。尤其是设置主题背景色后,程序从后台到前台ui界面没加载出来会显示出短暂的标题栏的颜色,因此设置主题背景颜色的方式还是有些缺陷。

废话不多说,我介绍的这个方法使用了小米的一个类:SystemBarTintManager

小米官网的地址 http://dev.xiaomi.com/doc/p=4769/index.html

经过测试在其他的手机上一样适用,只是那个设置标题栏字体颜色为黑色不能用而已。

  1 /*
  2  * Copyright (C) 2013 readyState Software Ltd
  3  *
  4  * Licensed under the Apache License, Version 2.0 (the "License");
  5  * you may not use this file except in compliance with the License.
  6  * You may obtain a copy of the License at
  7  *
  8  *      http://www.apache.org/licenses/LICENSE-2.0
  9  *
 10  * Unless required by applicable law or agreed to in writing, software
 11  * distributed under the License is distributed on an "AS IS" BASIS,
 12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  * See the License for the specific language governing permissions and
 14  * limitations under the License.
 15  */
 16 
 17 package com.readystatesoftware.systembartint;
 18 
 19 import java.lang.reflect.Field;
 20 import java.lang.reflect.Method;
 21 
 22 import android.annotation.SuppressLint;
 23 import android.annotation.TargetApi;
 24 import android.app.Activity;
 25 import android.content.Context;
 26 import android.content.res.Configuration;
 27 import android.content.res.Resources;
 28 import android.content.res.TypedArray;
 29 import android.graphics.drawable.Drawable;
 30 import android.os.Build;
 31 import android.util.DisplayMetrics;
 32 import android.util.TypedValue;
 33 import android.view.Gravity;
 34 import android.view.View;
 35 import android.view.ViewConfiguration;
 36 import android.view.ViewGroup;
 37 import android.view.Window;
 38 import android.view.WindowManager;
 39 import android.widget.FrameLayout.LayoutParams;
 40 
 41 /**
 42  * Class to manage status and navigation bar tint effects when using KitKat
 43  * translucent system UI modes.
 44  *
 45  */
 46 public class SystemBarTintManager {
 47 
 48     /**
 49      * The default system bar tint color value.
 50      */
 51     public static final int DEFAULT_TINT_COLOR = 0x99000000;
 52 
 53     private final SystemBarConfig mConfig;
 54     private boolean mStatusBarAvailable;
 55     private boolean mNavBarAvailable;
 56     private boolean mStatusBarTintEnabled;
 57     private boolean mNavBarTintEnabled;
 58     private View mStatusBarTintView;
 59     private View mNavBarTintView;
 60     private static boolean sIsMiuiV6;
 61 
 62     static {
 63         try {
 64             Class<?> sysClass = Class.forName("android.os.SystemProperties");
 65             Method getStringMethod = sysClass.getDeclaredMethod("get", String.class);
 66             sIsMiuiV6 = "V6".equals((String) getStringMethod.invoke(sysClass, "ro.miui.ui.version.name"));
 67         } catch (Exception e) {
 68             e.printStackTrace();
 69         }
 70     }
 71 
 72     /**
 73      * Constructor. Call this in the host activity onCreate method after its
 74      * content view has been set. You should always create new instances when
 75      * the host activity is recreated.
 76      *
 77      * @param activity The host activity.
 78      */
 79     @TargetApi(19)
 80     public SystemBarTintManager(Activity activity) {
 81 
 82         Window win = activity.getWindow();
 83         ViewGroup decorViewGroup = (ViewGroup) win.getDecorView();
 84 
 85         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
 86             // check theme attrs
 87             int[] attrs = {android.R.attr.windowTranslucentStatus,
 88                     android.R.attr.windowTranslucentNavigation};
 89             TypedArray a = activity.obtainStyledAttributes(attrs);
 90             try {
 91                 mStatusBarAvailable = a.getBoolean(0, false);
 92                 mNavBarAvailable = a.getBoolean(1, false);
 93             } finally {
 94                 a.recycle();
 95             }
 96 
 97             // check window flags
 98             WindowManager.LayoutParams winParams = win.getAttributes();
 99             int bits = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
100             if ((winParams.flags & bits) != 0) {
101                 mStatusBarAvailable = true;
102             }
103             bits = WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
104             if ((winParams.flags & bits) != 0) {
105                 mNavBarAvailable = true;
106             }
107         }
108 
109         mConfig = new SystemBarConfig(activity, mStatusBarAvailable, mNavBarAvailable);
110         // device might not have virtual navigation keys
111         if (!mConfig.hasNavigtionBar()) {
112             mNavBarAvailable = false;
113         }
114 
115         if (mStatusBarAvailable) {
116             setupStatusBarView(activity, decorViewGroup);
117         }
118         if (mNavBarAvailable) {
119             setupNavBarView(activity, decorViewGroup);
120         }
121 
122     }
123 
124     /**
125      * Enable tinting of the system status bar.
126      *
127      * If the platform is running Jelly Bean or earlier, or translucent system
128      * UI modes have not been enabled in either the theme or via window flags,
129      * then this method does nothing.
130      *
131      * @param enabled True to enable tinting, false to disable it (default).
132      */
133     public void setStatusBarTintEnabled(boolean enabled) {
134         mStatusBarTintEnabled = enabled;
135         if (mStatusBarAvailable) {
136             mStatusBarTintView.setVisibility(enabled ? View.VISIBLE : View.GONE);
137         }
138     }
139 
140     /**
141      * set status bar darkmode
142      * @param darkmode
143      * @param activity
144      */
145     public void setStatusBarDarkMode(boolean darkmode, Activity activity) {
146         if (sIsMiuiV6) {
147             Class<? extends Window> clazz = activity.getWindow().getClass();
148             try {
149             int darkModeFlag = 0;
150             Class<?> layoutParams = Class.forName("android.view.MiuiWindowManager$LayoutParams");
151             Field field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_DARK_MODE");
152             darkModeFlag = field.getInt(layoutParams);
153             Method extraFlagField = clazz.getMethod("setExtraFlags", int.class, int.class);
154             extraFlagField.invoke(activity.getWindow(), darkmode ? darkModeFlag : 0, darkModeFlag);
155             } catch (Exception e) {
156                 e.printStackTrace();
157             }
158         }
159     }
160 
161     /**
162      * Enable tinting of the system navigation bar.
163      *
164      * If the platform does not have soft navigation keys, is running Jelly Bean
165      * or earlier, or translucent system UI modes have not been enabled in either
166      * the theme or via window flags, then this method does nothing.
167      *
168      * @param enabled True to enable tinting, false to disable it (default).
169      */
170     public void setNavigationBarTintEnabled(boolean enabled) {
171         mNavBarTintEnabled = enabled;
172         if (mNavBarAvailable) {
173             mNavBarTintView.setVisibility(enabled ? View.VISIBLE : View.GONE);
174         }
175     }
176 
177     /**
178      * Apply the specified color tint to all system UI bars.
179      *
180      * @param color The color of the background tint.
181      */
182     public void setTintColor(int color) {
183         setStatusBarTintColor(color);
184         setNavigationBarTintColor(color);
185     }
186 
187     /**
188      * Apply the specified drawable or color resource to all system UI bars.
189      *
190      * @param res The identifier of the resource.
191      */
192     public void setTintResource(int res) {
193         setStatusBarTintResource(res);
194         setNavigationBarTintResource(res);
195     }
196 
197     /**
198      * Apply the specified drawable to all system UI bars.
199      *
200      * @param drawable The drawable to use as the background, or null to remove it.
201      */
202     public void setTintDrawable(Drawable drawable) {
203         setStatusBarTintDrawable(drawable);
204         setNavigationBarTintDrawable(drawable);
205     }
206 
207     /**
208      * Apply the specified alpha to all system UI bars.
209      *
210      * @param alpha The alpha to use
211      */
212     public void setTintAlpha(float alpha) {
213         setStatusBarAlpha(alpha);
214         setNavigationBarAlpha(alpha);
215     }
216 
217     /**
218      * Apply the specified color tint to the system status bar.
219      *
220      * @param color The color of the background tint.
221      */
222     public void setStatusBarTintColor(int color) {
223         if (mStatusBarAvailable) {
224             mStatusBarTintView.setBackgroundColor(color);
225         }
226     }
227 
228     /**
229      * Apply the specified drawable or color resource to the system status bar.
230      *
231      * @param res The identifier of the resource.
232      */
233     public void setStatusBarTintResource(int res) {
234         if (mStatusBarAvailable) {
235             mStatusBarTintView.setBackgroundResource(res);
236         }
237     }
238 
239     /**
240      * Apply the specified drawable to the system status bar.
241      *
242      * @param drawable The drawable to use as the background, or null to remove it.
243      */
244     @SuppressWarnings("deprecation")
245     public void setStatusBarTintDrawable(Drawable drawable) {
246         if (mStatusBarAvailable) {
247             mStatusBarTintView.setBackgroundDrawable(drawable);
248         }
249     }
250 
251     /**
252      * Apply the specified alpha to the system status bar.
253      *
254      * @param alpha The alpha to use
255      */
256     @TargetApi(11)
257     public void setStatusBarAlpha(float alpha) {
258         if (mStatusBarAvailable && Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
259             mStatusBarTintView.setAlpha(alpha);
260         }
261     }
262 
263     /**
264      * Apply the specified color tint to the system navigation bar.
265      *
266      * @param color The color of the background tint.
267      */
268     public void setNavigationBarTintColor(int color) {
269         if (mNavBarAvailable) {
270             mNavBarTintView.setBackgroundColor(color);
271         }
272     }
273 
274     /**
275      * Apply the specified drawable or color resource to the system navigation bar.
276      *
277      * @param res The identifier of the resource.
278      */
279     public void setNavigationBarTintResource(int res) {
280         if (mNavBarAvailable) {
281             mNavBarTintView.setBackgroundResource(res);
282         }
283     }
284 
285     /**
286      * Apply the specified drawable to the system navigation bar.
287      *
288      * @param drawable The drawable to use as the background, or null to remove it.
289      */
290     @SuppressWarnings("deprecation")
291     public void setNavigationBarTintDrawable(Drawable drawable) {
292         if (mNavBarAvailable) {
293             mNavBarTintView.setBackgroundDrawable(drawable);
294         }
295     }
296 
297     /**
298      * Apply the specified alpha to the system navigation bar.
299      *
300      * @param alpha The alpha to use
301      */
302     @TargetApi(11)
303     public void setNavigationBarAlpha(float alpha) {
304         if (mNavBarAvailable && Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
305             mNavBarTintView.setAlpha(alpha);
306         }
307     }
308 
309     /**
310      * Get the system bar configuration.
311      *
312      * @return The system bar configuration for the current device configuration.
313      */
314     public SystemBarConfig getConfig() {
315         return mConfig;
316     }
317 
318     /**
319      * Is tinting enabled for the system status bar?
320      *
321      * @return True if enabled, False otherwise.
322      */
323     public boolean isStatusBarTintEnabled() {
324         return mStatusBarTintEnabled;
325     }
326 
327     /**
328      * Is tinting enabled for the system navigation bar?
329      *
330      * @return True if enabled, False otherwise.
331      */
332     public boolean isNavBarTintEnabled() {
333         return mNavBarTintEnabled;
334     }
335 
336     private void setupStatusBarView(Context context, ViewGroup decorViewGroup) {
337         mStatusBarTintView = new View(context);
338         LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, mConfig.getStatusBarHeight());
339         params.gravity = Gravity.TOP;
340         if (mNavBarAvailable && !mConfig.isNavigationAtBottom()) {
341             params.rightMargin = mConfig.getNavigationBarWidth();
342         }
343         mStatusBarTintView.setLayoutParams(params);
344         mStatusBarTintView.setBackgroundColor(DEFAULT_TINT_COLOR);
345         mStatusBarTintView.setVisibility(View.GONE);
346         decorViewGroup.addView(mStatusBarTintView);
347     }
348 
349     private void setupNavBarView(Context context, ViewGroup decorViewGroup) {
350         mNavBarTintView = new View(context);
351         LayoutParams params;
352         if (mConfig.isNavigationAtBottom()) {
353             params = new LayoutParams(LayoutParams.MATCH_PARENT, mConfig.getNavigationBarHeight());
354             params.gravity = Gravity.BOTTOM;
355         } else {
356             params = new LayoutParams(mConfig.getNavigationBarWidth(), LayoutParams.MATCH_PARENT);
357             params.gravity = Gravity.RIGHT;
358         }
359         mNavBarTintView.setLayoutParams(params);
360         mNavBarTintView.setBackgroundColor(DEFAULT_TINT_COLOR);
361         mNavBarTintView.setVisibility(View.GONE);
362         decorViewGroup.addView(mNavBarTintView);
363     }
364 
365     /**
366      * Class which describes system bar sizing and other characteristics for the current
367      * device configuration.
368      *
369      */
370     public static class SystemBarConfig {
371 
372         private static final String STATUS_BAR_HEIGHT_RES_NAME = "status_bar_height";
373         private static final String NAV_BAR_HEIGHT_RES_NAME = "navigation_bar_height";
374         private static final String NAV_BAR_HEIGHT_LANDSCAPE_RES_NAME = "navigation_bar_height_landscape";
375         private static final String NAV_BAR_WIDTH_RES_NAME = "navigation_bar_width";
376 
377         private final boolean mTranslucentStatusBar;
378         private final boolean mTranslucentNavBar;
379         private final int mStatusBarHeight;
380         private final int mActionBarHeight;
381         private final boolean mHasNavigationBar;
382         private final int mNavigationBarHeight;
383         private final int mNavigationBarWidth;
384         private final boolean mInPortrait;
385         private final float mSmallestWidthDp;
386 
387         private SystemBarConfig(Activity activity, boolean translucentStatusBar, boolean traslucentNavBar) {
388             Resources res = activity.getResources();
389             mInPortrait = (res.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT);
390             mSmallestWidthDp = getSmallestWidthDp(activity);
391             mStatusBarHeight = getInternalDimensionSize(res, STATUS_BAR_HEIGHT_RES_NAME);
392             mActionBarHeight = getActionBarHeight(activity);
393             mNavigationBarHeight = getNavigationBarHeight(activity);
394             mNavigationBarWidth = getNavigationBarWidth(activity);
395             mHasNavigationBar = (mNavigationBarHeight > 0);
396             mTranslucentStatusBar = translucentStatusBar;
397             mTranslucentNavBar = traslucentNavBar;
398         }
399 
400         @TargetApi(14)
401         private int getActionBarHeight(Context context) {
402             int result = 0;
403             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
404                 TypedValue tv = new TypedValue();
405                 context.getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true);
406                 result = context.getResources().getDimensionPixelSize(tv.resourceId);
407             }
408             return result;
409         }
410 
411         @TargetApi(14)
412         private int getNavigationBarHeight(Context context) {
413             Resources res = context.getResources();
414             int result = 0;
415             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
416                 if (!ViewConfiguration.get(context).hasPermanentMenuKey()) {
417                     String key;
418                     if (mInPortrait) {
419                         key = NAV_BAR_HEIGHT_RES_NAME;
420                     } else {
421                         key = NAV_BAR_HEIGHT_LANDSCAPE_RES_NAME;
422                     }
423                     return getInternalDimensionSize(res, key);
424                 }
425             }
426             return result;
427         }
428 
429         @TargetApi(14)
430         private int getNavigationBarWidth(Context context) {
431             Resources res = context.getResources();
432             int result = 0;
433             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
434                 if (!ViewConfiguration.get(context).hasPermanentMenuKey()) {
435                     return getInternalDimensionSize(res, NAV_BAR_WIDTH_RES_NAME);
436                 }
437             }
438             return result;
439         }
440 
441         private int getInternalDimensionSize(Resources res, String key) {
442             int result = 0;
443             int resourceId = res.getIdentifier(key, "dimen", "android");
444             if (resourceId > 0) {
445                 result = res.getDimensionPixelSize(resourceId);
446             }
447             return result;
448         }
449 
450         @SuppressLint("NewApi")
451         private float getSmallestWidthDp(Activity activity) {
452             DisplayMetrics metrics = new DisplayMetrics();
453             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
454                 activity.getWindowManager().getDefaultDisplay().getRealMetrics(metrics);
455             } else {
456                 // TODO this is not correct, but we don't really care pre-kitkat
457                 activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
458             }
459             float widthDp = metrics.widthPixels / metrics.density;
460             float heightDp = metrics.heightPixels / metrics.density;
461             return Math.min(widthDp, heightDp);
462         }
463 
464         /**
465          * Should a navigation bar appear at the bottom of the screen in the current
466          * device configuration? A navigation bar may appear on the right side of
467          * the screen in certain configurations.
468          *
469          * @return True if navigation should appear at the bottom of the screen, False otherwise.
470          */
471         public boolean isNavigationAtBottom() {
472             return (mSmallestWidthDp >= 600 || mInPortrait);
473         }
474 
475         /**
476          * Get the height of the system status bar.
477          *
478          * @return The height of the status bar (in pixels).
479          */
480         public int getStatusBarHeight() {
481             return mStatusBarHeight;
482         }
483 
484         /**
485          * Get the height of the action bar.
486          *
487          * @return The height of the action bar (in pixels).
488          */
489         public int getActionBarHeight() {
490             return mActionBarHeight;
491         }
492 
493         /**
494          * Does this device have a system navigation bar?
495          *
496          * @return True if this device uses soft key navigation, False otherwise.
497          */
498         public boolean hasNavigtionBar() {
499             return mHasNavigationBar;
500         }
501 
502         /**
503          * Get the height of the system navigation bar.
504          *
505          * @return The height of the navigation bar (in pixels). If the device does not have
506          * soft navigation keys, this will always return 0.
507          */
508         public int getNavigationBarHeight() {
509             return mNavigationBarHeight;
510         }
511 
512         /**
513          * Get the width of the system navigation bar when it is placed vertically on the screen.
514          *
515          * @return The width of the navigation bar (in pixels). If the device does not have
516          * soft navigation keys, this will always return 0.
517          */
518         public int getNavigationBarWidth() {
519             return mNavigationBarWidth;
520         }
521 
522         /**
523          * Get the layout inset for any system UI that appears at the top of the screen.
524          *
525          * @param withActionBar True to include the height of the action bar, False otherwise.
526          * @return The layout inset (in pixels).
527          */
528         public int getPixelInsetTop(boolean withActionBar) {
529             return (mTranslucentStatusBar ? mStatusBarHeight : 0) + (withActionBar ? mActionBarHeight : 0);
530         }
531 
532         /**
533          * Get the layout inset for any system UI that appears at the bottom of the screen.
534          *
535          * @return The layout inset (in pixels).
536          */
537         public int getPixelInsetBottom() {
538             if (mTranslucentNavBar && isNavigationAtBottom()) {
539                 return mNavigationBarHeight;
540             } else {
541                 return 0;
542             }
543         }
544 
545         /**
546          * Get the layout inset for any system UI that appears at the right of the screen.
547          *
548          * @return The layout inset (in pixels).
549          */
550         public int getPixelInsetRight() {
551             if (mTranslucentNavBar && !isNavigationAtBottom()) {
552                 return mNavigationBarWidth;
553             } else {
554                 return 0;
555             }
556         }
557 
558     }
559 
560 }

使用起来也很简单,在你的activity或者baseactivity的oncreate方法中加入以下代码:

1 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
2             setTranslucentStatus(true);
3         }
4         mTintManager = new SystemBarTintManager(this);
5         mTintManager.setStatusBarTintEnabled(true);
6         //使StatusBarTintView 和 actionbar的颜色保持一致,风格统一。
7         mTintManager.setStatusBarTintResource(R.color.navbar);
8         // 设置状态栏的文字颜色
9         mTintManager.setStatusBarDarkMode(false, this);

setTranslucentStatus方法

 1 @TargetApi(19)
 2     protected void setTranslucentStatus(boolean on) {
 3         Window win = getWindow();
 4         WindowManager.LayoutParams winParams = win.getAttributes();
 5         final int bits = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
 6         if (on) {
 7             winParams.flags |= bits;
 8         } else {
 9             winParams.flags &= ~bits;
10         }
11         win.setAttributes(winParams);
12     }

然后需要在你的布局文件最外层添加以下代码

 1 android:fitsSystemWindows="true"

2 android:clipToPadding="false" 这个在设置主题的那里是设置为true的,注意区分

如果你只用了普通的activity,那么一切事情都已经结束了。但我做的司信项目,在主界面上用的是一个activitygroup,然后用tabhost添加了4个activity,这样的话会有一些出入,需要在activitygroup的方法上写上以上代码,activity继承了baseactivity,因此也加入了这些属性,会造成自定义的导航栏文字显示不全。

这个时候就再调用一下

mTintManager.setStatusBarTintEnabled(false);//把自定义的titlebar设置不显示

这样就可以了,效果是与之前的一样的,因此不再贴图。好处就是不会忽然闪一下之前的红色背景了。
原文地址:https://www.cnblogs.com/dongweiq/p/4448074.html