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 =)]
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(, false);
mNavBarAvailable = a.GetBoolean(, false);
}
finally
{
a.Recycle();
} // check window flags
WindowManagerLayoutParams winParams = win.Attributes;
if ((winParams.Flags & WindowManagerFlags.TranslucentStatus) != )
{
mStatusBarAvailable = true;
}
if ((winParams.Flags & WindowManagerFlags.TranslucentNavigation) != )
{
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 = )]
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 = )]
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(, Tool.dip2px(context, ), , );
} 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 > );
mTranslucentStatusBar = translucentStatusBar;
mTranslucentNavBar = traslucentNavBar;
} [TargetApi(Value = )]
private int getActionBarHeight(Context context)
{
int result = ;
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 = )]
private int getNavigationBarHeight(Context context)
{
Resources res = context.Resources;
int result = ;
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 = )]
private int getNavigationBarWidth(Context context)
{
Resources res = context.Resources;
int result = ;
if (Build.VERSION.SdkInt >= BuildVersionCodes.IceCreamSandwich)
{
if (hasNavBar(context))
{
return getInternalDimensionSize(res, NAV_BAR_WIDTH_RES_NAME);
}
}
return result;
} [TargetApi(Value = )]
private bool hasNavBar(Context context)
{
Resources res = context.Resources;
int resourceId = res.GetIdentifier(SHOW_NAV_BAR_RES_NAME, "bool", "android");
if (resourceId != )
{
bool hasNav = res.GetBoolean(resourceId);
// check override flag (see static block)
if ("".Equals(sNavBarOverride))
{
hasNav = false;
}
else if ("".Equals(sNavBarOverride))
{
hasNav = true;
}
return hasNav;
}
else
{ // fallback
return !ViewConfiguration.Get(context).HasPermanentMenuKey;
}
} private int getInternalDimensionSize(Resources res, string key)
{
int result = ;
int resourceId = res.GetIdentifier(key, "dimen", "android");
if (resourceId > )
{
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 >= || 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 : ) + (withActionBar ? mActionBarHeight : );
} /**
* 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 ;
}
} /**
* 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 ;
}
}
}
}
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 = )]
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;
}