Android 沉浸式状态栏 SystemStatusManager源码

苹果上的UI基本上都是这个效果,然而Android机上的顶部状态栏总是和app的主题颜色不搭。还好如今的api19以上的版本,我们也能做出这样的效果。




第一步:

[java]  view plain  copy
  1.         // 需要setContentView之前调用  
  2.         private void setTranslucentStatus() {  
  3.         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {  
  4.             // 透明状态栏  
  5.             getWindow().addFlags(  
  6.                     WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);  
  7.             // 透明导航栏  
  8.             getWindow().addFlags(  
  9.                     WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);  
  10.                         SystemStatusManager tintManager = new SystemStatusManager(this);  
  11.             tintManager.setStatusBarTintEnabled(true);  
  12.                         // 设置状态栏的颜色   
  13.                         tintManager.setStatusBarTintResource(R.color.theme_color);  
  14.             getWindow().getDecorView().setFitsSystemWindows(true);  
  15.         }  
  16.     }  
第二步:

为xml 的根布局添加android:fitsSystemWindows="true" 属性

第三步:SystemStatusManager 源码

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值