public class SystemBarTintManager { /** * The default system bar tint color value. */ public static Color DEFAULT_TINT_COLOR = Color.Black; private static string sNavBarOverride; private SystemBarConfig mConfig; private bool mStatusBarAvailable; private bool mNavBarAvailable; private bool mStatusBarTintEnabled; private bool mNavBarTintEnabled; private View mStatusBarTintView; private View mNavBarTintView; private Activity activity; static SystemBarTintManager() { // Android allows a system property to override the presence of the navigation bar. // Used by the emulator. // See https://github.com/android/platform_frameworks_base/blob/master/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java#L1076 if (Build.VERSION.SdkInt >= BuildVersionCodes.Kitkat) { try { Class c = Class.ForName("android.os.SystemProperties"); Method m = c.GetDeclaredMethod("get"); m.Accessible = true; sNavBarOverride = (string)m.Invoke(null, "qemu.hw.mainkeys"); } catch (Throwable) { sNavBarOverride = null; } } } /// <summary> /// 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. /// </summary> /// <param name="activity"></param> [TargetApi(Value =19)] public SystemBarTintManager(Activity activity) { this.activity = activity; Window win = activity.Window; ViewGroup decorViewGroup = (ViewGroup)win.DecorView; if (Build.VERSION.SdkInt >= BuildVersionCodes.Kitkat) { // check theme attrs int[] attrs = {Android.Resource.Attribute.WindowTranslucentStatus, Android.Resource.Attribute.WindowTranslucentNavigation}; TypedArray a = activity.ObtainStyledAttributes(attrs); try { mStatusBarAvailable = a.GetBoolean(0, false); mNavBarAvailable = a.GetBoolean(1, false); } finally { a.Recycle(); } // check window flags WindowManagerLayoutParams winParams = win.Attributes; if ((winParams.Flags & WindowManagerFlags.TranslucentStatus) != 0) { mStatusBarAvailable = true; } if ((winParams.Flags & WindowManagerFlags.TranslucentNavigation) != 0) { mNavBarAvailable = true; } } mConfig = new SystemBarConfig(activity, mStatusBarAvailable, mNavBarAvailable); // device might not have virtual navigation keys if (!mConfig.hasNavigtionBar()) { mNavBarAvailable = false; } if (mStatusBarAvailable) { setupStatusBarView(activity, decorViewGroup); } if (mNavBarAvailable) { setupNavBarView(activity, decorViewGroup); } } /** * Enable tinting of the system status bar. * * If the platform is running Jelly Bean or earlier, or translucent system * UI modes have not been enabled in either the theme or via window flags, * then this method does nothing. * * @param enabled True to enable tinting, false to disable it (default). */ public void setStatusBarTintEnabled(bool enabled) { mStatusBarTintEnabled = enabled; if (mStatusBarAvailable) { mStatusBarTintView.Visibility = enabled ? ViewStates.Visible : ViewStates.Gone; } } /** * Enable tinting of the system navigation bar. * * If the platform does not have soft navigation keys, is running Jelly Bean * or earlier, or translucent system UI modes have not been enabled in either * the theme or via window flags, then this method does nothing. * * @param enabled True to enable tinting, false to disable it (default). */ public void setNavigationBarTintEnabled(bool enabled) { mNavBarTintEnabled = enabled; if (mNavBarAvailable) { mNavBarTintView.Visibility=enabled ? ViewStates.Visible : ViewStates.Gone; } } /** * Apply the specified color tint to all system UI bars. * * @param color The color of the background tint. */ public void setTintColor(Color color) { setStatusBarTintColor(color); setNavigationBarTintColor(color); } /** * Apply the specified drawable or color resource to all system UI bars. * * @param res The identifier of the resource. */ public void setTintResource(int res) { setStatusBarTintResource(res); setNavigationBarTintResource(res); } /** * Apply the specified drawable to all system UI bars. * * @param drawable The drawable to use as the background, or null to remove it. */ public void setTintDrawable(Drawable drawable) { setStatusBarTintDrawable(drawable); setNavigationBarTintDrawable(drawable); } /** * Apply the specified alpha to all system UI bars. * * @param alpha The alpha to use */ public void setTintAlpha(float alpha) { setStatusBarAlpha(alpha); setNavigationBarAlpha(alpha); } /** * Apply the specified color tint to the system status bar. * * @param color The color of the background tint. */ public void setStatusBarTintColor(Color color) { if (mStatusBarAvailable) { mStatusBarTintView.SetBackgroundColor(color); } } /** * Apply the specified drawable or color resource to the system status bar. * * @param res The identifier of the resource. */ public void setStatusBarTintResource(int res) { if (mStatusBarAvailable) { mStatusBarTintView.SetBackgroundResource(res); } } /** * Apply the specified drawable to the system status bar. * * @param drawable The drawable to use as the background, or null to remove it. */ [SuppressWarnings(Value =new[] { "deprecation" })] public void setStatusBarTintDrawable(Drawable drawable) { if (mStatusBarAvailable) { mStatusBarTintView.SetBackgroundDrawable(drawable); } } /** * Apply the specified alpha to the system status bar. * * @param alpha The alpha to use */ [TargetApi( Value = 11)] public void setStatusBarAlpha(float alpha) { if (mStatusBarAvailable && Build.VERSION.SdkInt >= BuildVersionCodes.Honeycomb) { mStatusBarTintView.Alpha = alpha; } } /** * Apply the specified color tint to the system navigation bar. * * @param color The color of the background tint. */ public void setNavigationBarTintColor(Color color) { if (mNavBarAvailable) { mNavBarTintView.SetBackgroundColor(color); } } /** * Apply the specified drawable or color resource to the system navigation bar. * * @param res The identifier of the resource. */ public void setNavigationBarTintResource(int res) { if (mNavBarAvailable) mNavBarTintView.SetBackgroundResource(res); } /** * Apply the specified drawable to the system navigation bar. * * @param drawable The drawable to use as the background, or null to remove it. */ [SuppressWarnings( Value = new string[] { "deprecation" })] public void setNavigationBarTintDrawable(Drawable drawable) { if (mNavBarAvailable) { mNavBarTintView.SetBackgroundDrawable(drawable); } } /** * Apply the specified alpha to the system navigation bar. * * @param alpha The alpha to use */ [TargetApi(Value = 11)] public void setNavigationBarAlpha(float alpha) { if (mNavBarAvailable && Build.VERSION.SdkInt >= BuildVersionCodes.Honeycomb) { mNavBarTintView.Alpha=alpha; } } /** * Get the system bar configuration. * * @return The system bar configuration for the current device configuration. */ public SystemBarConfig getConfig() { return mConfig; } /** * Is tinting enabled for the system status bar? * * @return True if enabled, False otherwise. */ public bool isStatusBarTintEnabled() { return mStatusBarTintEnabled; } /** * Is tinting enabled for the system navigation bar? * * @return True if enabled, False otherwise. */ public bool isNavBarTintEnabled() { return mNavBarTintEnabled; } private void setupStatusBarView(Context context, ViewGroup decorViewGroup) { mStatusBarTintView = new View(context); LayoutParams param = new LayoutParams(LayoutParams.MatchParent, mConfig.getStatusBarHeight()); param.Gravity = GravityFlags.Top; if (mNavBarAvailable && !mConfig.isNavigationAtBottom()) { param.RightMargin = mConfig.getNavigationBarWidth(); } mStatusBarTintView.LayoutParameters = param; mStatusBarTintView.SetBackgroundColor(DEFAULT_TINT_COLOR); mStatusBarTintView.Visibility = ViewStates.Gone; decorViewGroup.AddView(mStatusBarTintView); var view = getRootView(activity); view.SetPadding(0, Tool.dip2px(context, 73), 0, 0); } private static View getRootView(Activity context) { return context.FindViewById(Android.Resource.Id.Content); } private void setupNavBarView(Context context, ViewGroup decorViewGroup) { mNavBarTintView = new View(context); LayoutParams param = null; if (mConfig.isNavigationAtBottom()) { param = new LayoutParams(LayoutParams.MatchParent, mConfig.getNavigationBarHeight()); param.Gravity = GravityFlags.Bottom; } else { param = new LayoutParams(mConfig.getNavigationBarWidth(), LayoutParams.MatchParent); param.Gravity = GravityFlags.Right; } mNavBarTintView.LayoutParameters=param; mNavBarTintView.SetBackgroundColor(DEFAULT_TINT_COLOR); mNavBarTintView.Visibility= ViewStates.Gone; decorViewGroup.AddView(mNavBarTintView); } /// <summary> /// Class which describes system bar sizing and other characteristics for the current /// device configuration. /// </summary> public class SystemBarConfig { private static string STATUS_BAR_HEIGHT_RES_NAME = "status_bar_height"; private static string NAV_BAR_HEIGHT_RES_NAME = "navigation_bar_height"; private static string NAV_BAR_HEIGHT_LANDSCAPE_RES_NAME = "navigation_bar_height_landscape"; private static string NAV_BAR_WIDTH_RES_NAME = "navigation_bar_width"; private static string SHOW_NAV_BAR_RES_NAME = "config_showNavigationBar"; private bool mTranslucentStatusBar; private bool mTranslucentNavBar; private int mStatusBarHeight; private int mActionBarHeight; private bool mHasNavigationBar; private int mNavigationBarHeight; private int mNavigationBarWidth; private bool mInPortrait; private float mSmallestWidthDp; public SystemBarConfig(Activity activity, bool translucentStatusBar, bool traslucentNavBar) { Resources res = activity.Resources; mInPortrait = (res.Configuration.Orientation == Android.Content.Res.Orientation.Portrait); mSmallestWidthDp = getSmallestWidthDp(activity); mStatusBarHeight = getInternalDimensionSize(res, STATUS_BAR_HEIGHT_RES_NAME); mActionBarHeight = getActionBarHeight(activity); mNavigationBarHeight = getNavigationBarHeight(activity); mNavigationBarWidth = getNavigationBarWidth(activity); mHasNavigationBar = (mNavigationBarHeight > 0); mTranslucentStatusBar = translucentStatusBar; mTranslucentNavBar = traslucentNavBar; } [TargetApi(Value = 14)] private int getActionBarHeight(Context context) { int result = 0; if (Build.VERSION.SdkInt >= BuildVersionCodes.IceCreamSandwich) { TypedValue tv = new TypedValue(); context.Theme.ResolveAttribute(Android.Resource.Attribute.ActionBarSize, tv, true); result = TypedValue.ComplexToDimensionPixelSize(tv.Data, context.Resources.DisplayMetrics); } return result; } [TargetApi(Value = 14)] private int getNavigationBarHeight(Context context) { Resources res = context.Resources; int result = 0; if (Build.VERSION.SdkInt >= BuildVersionCodes.IceCreamSandwich) { if (hasNavBar(context)) { string key; if (mInPortrait) { key = NAV_BAR_HEIGHT_RES_NAME; } else { key = NAV_BAR_HEIGHT_LANDSCAPE_RES_NAME; } return getInternalDimensionSize(res, key); } } return result; } [TargetApi(Value = 14)] private int getNavigationBarWidth(Context context) { Resources res = context.Resources; int result = 0; if (Build.VERSION.SdkInt >= BuildVersionCodes.IceCreamSandwich) { if (hasNavBar(context)) { return getInternalDimensionSize(res, NAV_BAR_WIDTH_RES_NAME); } } return result; } [TargetApi(Value = 14)] private bool hasNavBar(Context context) { Resources res = context.Resources; int resourceId = res.GetIdentifier(SHOW_NAV_BAR_RES_NAME, "bool", "android"); if (resourceId != 0) { bool hasNav = res.GetBoolean(resourceId); // check override flag (see static block) if ("1".Equals(sNavBarOverride)) { hasNav = false; } else if ("0".Equals(sNavBarOverride)) { hasNav = true; } return hasNav; } else { // fallback return !ViewConfiguration.Get(context).HasPermanentMenuKey; } } private int getInternalDimensionSize(Resources res, string key) { int result = 0; int resourceId = res.GetIdentifier(key, "dimen", "android"); if (resourceId > 0) { result = res.GetDimensionPixelSize(resourceId); } return result; } [SuppressLint(Value = new string[] { "NewApi" })] private float getSmallestWidthDp(Activity activity) { DisplayMetrics metrics = new DisplayMetrics(); if (Build.VERSION.SdkInt >= BuildVersionCodes.JellyBean) { activity.WindowManager.DefaultDisplay.GetRealMetrics(metrics); } else { // TODO this is not correct, but we don't really care pre-kitkat activity.WindowManager.DefaultDisplay.GetMetrics(metrics); } float widthDp = metrics.WidthPixels / metrics.Density; float heightDp = metrics.HeightPixels / metrics.Density; return Java.Lang.Math.Min(widthDp, heightDp); } /// <summary> /// * Should a navigation bar appear at the bottom of the screen in the current /// * device configuration? A navigation bar may appear on the right side of /// * the screen in certain configurations. /// * /// * @return True if navigation should appear at the bottom of the screen, False otherwise. /// </summary> /// <returns></returns> public bool isNavigationAtBottom() { return (mSmallestWidthDp >= 600 || mInPortrait); } /** * Get the height of the system status bar. * * @return The height of the status bar (in pixels). */ public int getStatusBarHeight() { return mStatusBarHeight; } /** * Get the height of the action bar. * * @return The height of the action bar (in pixels). */ public int getActionBarHeight() { return mActionBarHeight; } /** * Does this device have a system navigation bar? * * @return True if this device uses soft key navigation, False otherwise. */ public bool hasNavigtionBar() { return mHasNavigationBar; } /** * Get the height of the system navigation bar. * * @return The height of the navigation bar (in pixels). If the device does not have * soft navigation keys, this will always return 0. */ public int getNavigationBarHeight() { return mNavigationBarHeight; } /** * Get the width of the system navigation bar when it is placed vertically on the screen. * * @return The nbsp;width of the navigation bar (in pixels). If the device does not have * soft navigation keys, this will always return 0. */ public int getNavigationBarWidth() { return mNavigationBarWidth; } /** * Get the layout inset for any system UI that appears at the top of the screen. * * @param withActionBar True to include the height of the action bar, False otherwise. * @return The layout inset (in pixels). */ public int getPixelInsetTop(bool withActionBar) { return (mTranslucentStatusBar ? mStatusBarHeight : 0) + (withActionBar ? mActionBarHeight : 0); } /** * Get the layout inset for any system UI that appears at the bottom of the screen. * * @return The layout inset (in pixels). */ public int getPixelInsetBottom() { if (mTranslucentNavBar && isNavigationAtBottom()) { return mNavigationBarHeight; } else { return 0; } } /** * Get the layout inset for any system UI that appears at the right of the screen. * * @return The layout inset (in pixels). */ public int getPixelInsetRight() { if (mTranslucentNavBar && !isNavigationAtBottom()) { return mNavigationBarWidth; } else { return 0; } } } }
protected override void OnCreate(Bundle savedInstanceState) { /*状态栏沉浸效果*/ if (Build.VERSION.SdkInt >= BuildVersionCodes.Kitkat) setTranslucentStatus(this, true); SystemBarTintManager tintManager = new SystemBarTintManager(this); tintManager.setStatusBarTintEnabled(true); // 使用颜色资源 tintManager.setStatusBarTintResource(Resource.Color.main_color); base.OnCreate(savedInstanceState); }
[TargetApi(Value = 19)] private static void setTranslucentStatus(Activity activity, bool on) { Window win = activity.Window; WindowManagerLayoutParams winParams = win.Attributes; if (on) winParams.Flags = WindowManagerFlags.TranslucentStatus; else winParams.Flags &= ~WindowManagerFlags.TranslucentStatus; win.Attributes = winParams; }