Android Immersive Mode (沉浸模式) 还是 Translucent Bars (透明状态栏)

Immersive Mode (沉浸模式) 还是 Translucent Bars (透明状态栏)

【科普】什么叫真正的“沉浸式”状态栏?

为什么在国内会有很多用户把「透明栏」(Translucent Bars)称作 「沉浸式顶栏」?

MIUI 6 沉浸式状态栏调用方法

完全隐藏 System Bars 的 Immersive Mode, 在大部分时候 Translucent Bars 并不能营造沉浸式体验

当Android系统版本大于19(4.4),就可以开启透明标题栏:

可以将其封装成方法进行调用。

 1 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
 2             Window win = getWindow();
 3 
 4             WindowManager.LayoutParams winParams = win.getAttributes();
 5             winParams.flags |= WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
 6             win.setAttributes(winParams);
 7 
 8             SystemBarTintManager tintManager = new SystemBarTintManager(this);
 9             tintManager.setStatusBarTintEnabled(true);
10             tintManager.setStatusBarTintColor(Color.TRANSPARENT);
11         }

注意:

1. 单纯图片背景时,要使得视图xml根视图的,背景图全屏时,需要设置isFitsSystemWindows=false。

2.对于有TopBar的,需要设置根视图的paddingTop:

 1 mRootView.setPadding(0, getStatusBarHeight(mContext), 0, 0);
 2 // 通过反射获取状态栏高度
 3 public static int getStatusBarHeight(Context context) {
 4         try {
 5             Class<?> c = Class.forName("com.android.internal.R$dimen");
 6             Object obj = c.newInstance();
 7             Field field = c.getField("status_bar_height");
 8             int x = Integer.parseInt(field.get(obj).toString());
 9 
10             return context.getResources().getDimensionPixelSize(x);
11         } catch (Exception e) {
12             e.printStackTrace();
13         }
14 
15         return 0;
16     }

// 沉浸式状态栏 

Android UI ImmersiveMode沉浸模式

Android 沉浸式状态栏

其第三方源代码:

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