Android沉浸式状态栏实现

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

第一步:

  // 需要setContentView之前调用
  private void setTranslucentStatus() {
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
    // 透明状态栏
    getWindow().addFlags(
        WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
    // 透明导航栏
    getWindow().addFlags(
        WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
          SystemStatusManager tintManager = new SystemStatusManager(this);
    tintManager.setStatusBarTintEnabled(true);
          // 设置状态栏的颜色
          tintManager.setStatusBarTintResource(R.color.theme_color);
    getWindow().getDecorView().setFitsSystemWindows(true);
  }
}

第二步:

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

第三步:SystemStatusManager

import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.FrameLayout.LayoutParams;

import java.lang.reflect.Method;

@SuppressWarnings({ “unchecked”, “rawtypes” })
public class SystemStatusManager
{
static
{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
try {
Class c = Class.forName(“android.os.SystemProperties”);
Method m = c.getDeclaredMethod(“get”, String.class);
m.setAccessible(true);
sNavBarOverride = (String) m.invoke(null, “qemu.hw.mainkeys”);
} catch (Throwable e) {
sNavBarOverride = null;
}
}
}

/**
 * The default system bar tint color value.
 */
public static final int DEFAULT_TINT_COLOR = 0x99000000;
private static String sNavBarOverride;
private final SystemBarConfig mConfig;
private boolean mStatusBarAvailable;
private boolean mNavBarAvailable;
private boolean mStatusBarTintEnabled;
private boolean mNavBarTintEnabled;
private View mStatusBarTintView;
private View mNavBarTintView;

/**
 * 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.
 */
@TargetApi(19)
public SystemStatusManager(Activity activity) {

  Window win = activity.getWindow();
  ViewGroup decorViewGroup = (ViewGroup) win.getDecorView();

  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
    // check theme attrs
    int[] attrs = {android.R.attr.windowTranslucentStatus,
        android.R.attr.windowTranslucentNavigation};
    TypedArray a = activity.obtainStyledAttributes(attrs);
    try {
      mStatusBarAvailable = a.getBoolean(0, false);
      mNavBarAvailable = a.getBoolean(1, false);
    } finally {
      a.recycle();
    }

    // check window flags
    WindowManager.LayoutParams winParams = win.getAttributes();
    int bits = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
    if ((winParams.flags & bits) != 0) {
      mStatusBarAvailable = true;
    }
    bits = WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
    if ((winParams.flags & bits) != 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(boolean enabled) {
  mStatusBarTintEnabled = enabled;
  if (mStatusBarAvailable) {
    mStatusBarTintView.setVisibility(enabled ? View.VISIBLE : View.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(boolean enabled) {
  mNavBarTintEnabled = enabled;
  if (mNavBarAvailable) {
    mNavBarTintView.setVisibility(enabled ? View.VISIBLE : View.GONE);
  }
}

/**
 * Apply the specified color tint to all system UI bars.
 *
 * @param color The color of the background tint.
 */
public void setTintColor(int 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(int 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("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(11)
public void setStatusBarAlpha(float alpha) {
  if (mStatusBarAvailable && Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
    mStatusBarTintView.setAlpha(alpha);
  }
}

/**
 * Apply the specified color tint to the system navigation bar.
 *
 * @param color The color of the background tint.
 */
public void setNavigationBarTintColor(int 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("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(11)
public void setNavigationBarAlpha(float alpha) {
  if (mNavBarAvailable && Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
    mNavBarTintView.setAlpha(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 boolean isStatusBarTintEnabled() {
  return mStatusBarTintEnabled;
}

/**
 * Is tinting enabled for the system navigation bar?
 *
 * @return True if enabled, False otherwise.
 */
public boolean isNavBarTintEnabled() {
  return mNavBarTintEnabled;
}

private void setupStatusBarView(Context context, ViewGroup decorViewGroup) {
  mStatusBarTintView = new View(context);
  LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, mConfig.getStatusBarHeight());
  params.gravity = Gravity.TOP;
  if (mNavBarAvailable && !mConfig.isNavigationAtBottom()) {
    params.rightMargin = mConfig.getNavigationBarWidth();
  }
  mStatusBarTintView.setLayoutParams(params);
  mStatusBarTintView.setBackgroundColor(DEFAULT_TINT_COLOR);
  mStatusBarTintView.setVisibility(View.GONE);
  decorViewGroup.addView(mStatusBarTintView);
}

private void setupNavBarView(Context context, ViewGroup decorViewGroup) {
  mNavBarTintView = new View(context);
  LayoutParams params;
  if (mConfig.isNavigationAtBottom()) {
    params = new LayoutParams(LayoutParams.MATCH_PARENT, mConfig.getNavigationBarHeight());
    params.gravity = Gravity.BOTTOM;
  } else {
    params = new LayoutParams(mConfig.getNavigationBarWidth(), LayoutParams.MATCH_PARENT);
    params.gravity = Gravity.RIGHT;
  }
  mNavBarTintView.setLayoutParams(params);
  mNavBarTintView.setBackgroundColor(DEFAULT_TINT_COLOR);
  mNavBarTintView.setVisibility(View.GONE);
  decorViewGroup.addView(mNavBarTintView);
}

/**
 * Class which describes system bar sizing and other characteristics for the current
 * device configuration.
 *
 */
public static class SystemBarConfig {

  private static final String STATUS_BAR_HEIGHT_RES_NAME = "status_bar_height";
  private static final String NAV_BAR_HEIGHT_RES_NAME = "navigation_bar_height";
  private static final String NAV_BAR_HEIGHT_LANDSCAPE_RES_NAME = "navigation_bar_height_landscape";
  private static final String NAV_BAR_WIDTH_RES_NAME = "navigation_bar_width";
  private static final String SHOW_NAV_BAR_RES_NAME = "config_showNavigationBar";

  private final boolean mTranslucentStatusBar;
  private final boolean mTranslucentNavBar;
  private final int mStatusBarHeight;
  private final int mActionBarHeight;
  private final boolean mHasNavigationBar;
  private final int mNavigationBarHeight;
  private final int mNavigationBarWidth;
  private final boolean mInPortrait;
  private final float mSmallestWidthDp;

  private SystemBarConfig(Activity activity, boolean translucentStatusBar, boolean traslucentNavBar) {
    Resources res = activity.getResources();
    mInPortrait = (res.getConfiguration().orientation == Configuration.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(14)
  private int getActionBarHeight(Context context) {
    int result = 0;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
      TypedValue tv = new TypedValue();
      context.getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true);
      result = TypedValue.complexToDimensionPixelSize(tv.data, context.getResources().getDisplayMetrics());
    }
    return result;
  }

  @TargetApi(14)
  private int getNavigationBarHeight(Context context) {
    Resources res = context.getResources();
    int result = 0;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
      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(14)
  private int getNavigationBarWidth(Context context) {
    Resources res = context.getResources();
    int result = 0;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
      if (hasNavBar(context)) {
        return getInternalDimensionSize(res, NAV_BAR_WIDTH_RES_NAME);
      }
    }
    return result;
  }

  @TargetApi(14)
  private boolean hasNavBar(Context context) {
    Resources res = context.getResources();
    int resourceId = res.getIdentifier(SHOW_NAV_BAR_RES_NAME, "bool", "android");
    if (resourceId != 0) {
      boolean 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("NewApi")
  private float getSmallestWidthDp(Activity activity) {
    DisplayMetrics metrics = new DisplayMetrics();
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
      activity.getWindowManager().getDefaultDisplay().getRealMetrics(metrics);
    } else {
      activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
    }
    float widthDp = metrics.widthPixels / metrics.density;
    float heightDp = metrics.heightPixels / metrics.density;
    return Math.min(widthDp, heightDp);
  }

  /**
   * 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.
   */
  public boolean 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 boolean 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 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(boolean 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;
    }
  }

}
}

以上就是本文的全部内容,希望大家喜欢。

(0)

相关推荐

  • Android之沉浸式状态栏的实现方法、状态栏透明

    现在越来越多的软件都开始使用沉浸式状态栏了,下面总结一下沉浸式状态栏的两种使用方法 注意!沉浸式状态栏只支持安卓4.4及以上的版本 状态栏:4.4上是渐变色,5.0上是完全透明,本文模拟器为4.4演示 效果图: 注意!两种方法的区别: 第一种:为顶部栏跟随当前activity的布局文件的背景的颜色,使用方便,不过也有点问题就是,如果有底部虚拟导航键的话,导航键的背景跟顶部的颜色一样,比如: 第二种:是通过设置顶部栏的颜色来显示的,可以解决第一种的不足,比如: 第一种使用方法: 第一.首先在val

  • Android 实现沉浸式状态栏的方法

    沉浸式状态栏的来源就是很多手机用的是实体按键,没有虚拟键,于是开了沉浸模式就只有状态栏消失了.于是沉浸模式成了沉浸式状态栏. 我们先来看下具体的效果 开启沉浸模式后,状态栏消失,从顶部向下滑动,状态栏出现,退出沉浸模式,状态栏也出现了. 我们的代码基于前一篇文章.首先是两个开启沉浸模式和关闭沉浸模式的函数 @SuppressLint("NewApi") public static void hideSystemUI(View view) { view.setSystemUiVisibi

  • Android 沉浸式状态栏与隐藏导航栏实例详解

    1 前言 一般我们在Android的APP开发中,APP的界面如下: 可以看到,有状态栏.ActionBar(ToolBar).导航栏等,一般来说,APP实现沉浸式有三种需求:沉浸式状态栏,隐藏导航栏,APP全屏 沉浸式状态栏是指状态栏与ActionBar颜色相匹配, 隐藏导航栏不用多说,就是将导航栏隐藏,去掉下面的黑条. APP全屏是指将状态栏与导航栏都隐藏,例如很多游戏界面,都是APP全屏. 所以,在做这一步时,关键要问清楚产品狗的需求,免得白费功夫. 下面,分别来介绍这三种方式的实现. 2

  • 另外两种Android沉浸式状态栏实现思路

    关于沉浸式状态栏相信大家都不陌生,IOS系统很早就有,android5.0及以后版本都支持给状态栏着色,而目前android主流版本还是4.4,网上通用实现4.4(API19)沉浸式状态栏也都是依赖于可以将状态栏变为透明的属性,再为其着色,主要实现代码: @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout

  • Android沉浸式状态栏的实现代码

    沉浸式状态栏是Android4.4即api19以上才支持的特性,分两步实现: 1.在布局文件中第一个控件(一般是imageview或者textview)中添加两个属性. <!--沉浸式--> <ImageView android:fitsSystemWindows="true" android:clipToPadding="true" .../> 2.在Activity初始化view的时候,进行设置. if (Build.VERSION.SD

  • Android沉浸式状态栏微技巧(带你真正理解沉浸式模式)

    其实说到沉浸式状态栏这个名字我也是感到很无奈,真不知道这种叫法是谁先发起的.因为Android官方从来没有给出过沉浸式状态栏这样的命名,只有沉浸式模式(Immersive Mode)这种说法.而有些人在没有完全了解清楚沉浸模式到底是什么东西的情况下,就张冠李戴地认为一些系统提供的状态栏操作就是沉浸式的,并且还起了一个沉浸式状态栏的名字. 比如之前就有一个QQ群友问过我,像饿了么这样的沉浸式状态栏效果该如何实现? 这个效果其实就是让背景图片可以利用系统状态栏的空间,从而能够让背景图和状态栏融为一体

  • 解决Android 沉浸式状态栏和华为虚拟按键冲突问题

    对于现在的 App 来说,布局页面基本都会用到沉浸式状态栏,单纯的沉浸式状态栏很容易解决,但是在华为手机上存在一个底部虚拟按键的问题,会导致页面底部和顶部出现很大的问题,比如页面底部导航栏被按键覆盖,导致底部无法操作,顶部状态栏布局被撑的很高,丑的不忍直视,这里就将两者的冲突问题一并解决!先看下实现的效果图: 这是我自己的手机,OnePlus 3T 7.1.1版本(免费广告,没给我钱的啊),不是华为的手机,但是有个虚拟按键可以设置,可以看到底部导航栏没有问题,顶部状态栏也成功实现,效果图看完,下

  • Android 高仿QQ 沉浸式状态栏

    前言: 在进入今天正题前,还是老样子先谈谈感想吧,最近感觉整个都失去了方向感,好迷茫!找工作又失败了,难道Android真的饱和了?这两天我一直没出门,除了下楼哪外卖就是宅宿舍了,静想了许久,我还是不能忘了初心,我相信我找不到工作的原因有很多,最关键的还是要技术够硬才行啊,奔跑吧孩子!接下来我就给大家介绍怎样快速打造沉浸式状态栏吧,虽然感觉有点相见恨晚,但其实不完! 一:何为沉浸式状态栏? 沉浸式状态栏是Google从Android 4.4开始,给我们开发者提供的一套能透明的系统ui样式,这样样

  • Android 4.4以上"沉浸式"状态栏效果的实现方法

    什么是沉浸式状态栏? 沉浸式状态栏意思指状态栏的颜色随着软件颜色而改变,使状态栏和软件颜色保持一致,沉浸其中!当我们打开应用程序时,不会再因为看到应用程序和状态栏的黑边相隔开而感到十分难看.沉浸式状态栏由于其能给用户群体带来极佳的用户体验,已经在越来越多的应用上得到了体现. 实现原理 从4.4后系统增加了透明状态栏的特性WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS 一旦添加上这个属性后,那么布局中的内容DecorView就会自动填充到状态栏

  • Android App仿QQ制作Material Design风格沉浸式状态栏

    一.概述 近期注意到QQ新版使用了沉浸式状态栏,ok,先声明一下效果图: 恩,接下来正题. 首先只有大于等于4.4版本支持这个半透明状态栏的效果,但是4.4和5.0的显示效果有一定的差异,所有本文内容为: 1.如何实现半透明状态栏效果在大于4.4版本之上. 2.如何让4.4的效果与5.0的效果尽可能一致. 先贴下模拟器效果图,以便和实现过程中做下对比 4.4 模拟器 5.x 真机 二.实现半透明状态栏 因为本例使用了NavigationView,所以布局代码稍多,当然如果你不需要,可以自己进行筛

随机推荐