Immersive Mode (沉浸模式) 还是 Translucent Bars (透明状态栏)
完全隐藏 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 }
// 沉浸式状态栏
其第三方源代码:
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 Bean112 * or earlier, or translucent system UI modes have not been enabled in either113 * 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 use158 */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 use202 */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 use248 */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 current314 * 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 { // fallback403 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-kitkat423 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 current432 * device configuration? A navigation bar may appear on the right side of433 * 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 have472 * 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 have482 * 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