android沉浸式状态栏StatusBar在不同Window下的实现
StatusBar沉浸式的2种实现方式
对于沉浸式状态栏的实现,我觉得有两种实现方式。
一是:将状态栏的颜色和状态栏下面的View颜色保持一致或相近。如图:
二是:将View充满全屏,状态栏覆盖在View上,将状态栏设置为透明色。
StatusBar沉浸式实现的真相
我们使用Android Studio的提供的截图工具Layout Inspector工具分析可以知道,实际上显示时间、信号等SystemBar是系统级别的一个Window(悬浮窗)。而StatusBar是SystemBar下面的View,是DecorView的一部分。我们通常设置StatusBar的颜色其实就是给SystemBar覆盖的StatusBar设置一个背景色。
LayoutInspetor工具的截图:
由上图可知,StatusBar是DecorView的一部分,是一个View设置了背景色,没有系统的时间、信号等信息。
所以我们所设置状态栏的颜色,就是设置DecorView中的StatusBar的View的颜色。
上图说明:ImageView占满了怎个DecorView,没有StatusBar。
StatusBar的在不同Window上的实现
我们不管是Activity,Fragment还是在DialogFragment以及Window悬浮窗,都是有可能有使用沉浸式状态栏的。那么如何实现呢,以下实现是基于Android5.0以上,对Android4.4不兼容?
1. Activity和Fragment实现StatusBar的沉浸式
Activity和Fragment的实现StatusBar沉浸式的方式是一样的,我们知道Activity是依附于Window的,具体实现是PhoneWindow的DecorView。Fragment是依附于Activity的,所以可以通过获取Activity,在获取Window。来实现修改StatusBar的颜色。下面以Activity为例来分别看下2种实现方式,Fragment的实现方式会在demo的中分享到github上,不在此列举。
- 方式一:
public class MutilStatusBarActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
getWindow().requestFeature(Window.FEATURE_NO_TITLE);
super.onCreate(savedInstanceState);
StatusBarManager.getInstance().setStatusBar(getWindow(), Color.parseColor("#dd0000"));
setContentView(R.layout.activity_text);
final TextView imageView = (TextView) findViewById(R.id.image);
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ViewHelperUtils.click(getWindow(), imageView);
}
});
}
}
- 方式二:
public class ImageStatusBarActivity extends Activity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
getWindow().requestFeature(Window.FEATURE_NO_TITLE);
super.onCreate(savedInstanceState);
StatusBarManager.getInstance().setActivityWindowStyle(getWindow());
StatusBarManager.getInstance().setStatusBar(getWindow(), Color.TRANSPARENT);
setContentView(R.layout.common_image);
initView();
}
private void initView() {
ImageView imageView = (ImageView) findViewById(R.id.second_image);
ViewHelperUtils.setImageViewBitmap(imageView);
}
}
这里封装了2个类。
StatusBarManager:设置StatusBar的核心类
public class StatusBarManager {
private final static StatusBarManager ourInstance = new StatusBarManager();
public static StatusBarManager getInstance() {
return ourInstance;
}
private StatusBarManager() {
}
/**
* 设置StatusBar字体颜色
* <p>
* 参数true表示StatusBar风格为Light,字体颜色为黑色
* 参数false表示StatusBar风格不是Light,字体颜色为白色
* <p>
* <item name="android:windowLightStatusBar">true</item>
* 在theme或style中使用这个属性改变StatusBar的字体颜色,这种形式相对不灵活
*/
@TargetApi(Build.VERSION_CODES.M)
public void setStatusBarTextColor(Window window, boolean lightStatusBar) {
if (window == null) return;
View decor = window.getDecorView();
int ui = decor.getSystemUiVisibility();
if (lightStatusBar) {
ui |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
} else {
ui &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
}
decor.setSystemUiVisibility(ui);
}
/**
* 设置StatusBar的颜色
*/
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public void setStatusBar(Window window, @ColorInt int color) {
if (window == null) return;
window.setStatusBarColor(color);
}
/**
* 设置Dialog风格的Window的背景色
* <p>
* 这个和设置StatusBar的颜色有区别的,它是设置一个Window背景色,
* 这时StatusBar和Window的背景色保持一致,如果StatusBar下面的View背景色改变,会就盖住Window的背景色,界面就会丑陋,
* 如果想做到沉浸式,除非将StatusBar下面的View的颜色和Window的背景色同时改变
*/
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public void setDialogWindowStyle(Window window, @ColorInt int color) {
if (window == null) return;
window.setBackgroundDrawable(new ColorDrawable(color));
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
window.addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR);
window.addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN);
}
/**
* 设置Dialog风格的Window的StatusBar的颜色
* <p>
* 这种实现方式是将原本在StatusBar下面的View,直接固定到屏幕最上面,
* 这时StatusBar盖在View的上面,这时对View设置背景色,就像是沉浸式了
*/
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public void setDialogWindowStyle2(Window window) {
if (window == null) return;
window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));//设置window背景色为透明色
setActivityWindowStyle(window);
}
/**
* 设置Activity风格的Window的StatusBar的颜色
* <p>
* 这种实现方式是将原本在StatusBar下面的View,直接固定到屏幕最上面,
* 这时StatusBar盖在View的上面,如果这个View的背景设置的是一张图片,可以显示出很好的沉浸式效果。
* 如果View有图片,不要设置这个Window的属性,直接调用setStatusBar()方法
*/
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public void setActivityWindowStyle(Window window) {
if (window == null) return;
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
}
/**
* 通过WindowManager来设置沉浸式状态
* <p>
* 通过指定window的位置params.y来设置沉浸式,
* 这里的params.height是WRAP_CONTENT,才有效果,
* 如果是MATCH_PARENT会显示在最上面。
*/
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public void setWindowManagerStyle(final Window window, View view, boolean fullScreen) {
if (window == null) return;
WindowManager manager = window.getWindowManager();
WindowManager.LayoutParams params = window.getAttributes();
params.alpha = 1.0f;
params.width = WindowManager.LayoutParams.MATCH_PARENT;
params.height = fullScreen ? WindowManager.LayoutParams.MATCH_PARENT : WindowManager.LayoutParams.WRAP_CONTENT;
params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS
| WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
params.format = PixelFormat.RGBA_8888;
params.gravity = Gravity.START | Gravity.TOP;
params.x = 0;
params.y = fullScreen ? 0 : getStatusBarHeight(window.getContext());
manager.addView(view, params);
}
public int getStatusBarHeight(Context context) {
// 获得状态栏高度
int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
return context.getResources().getDimensionPixelSize(resourceId);
}
}
ViewHelperUtils:对View操作控制的类
public class ViewHelperUtils {
private final static int RED = 0;
private final static int YELLOW = 1;
private final static int GREEN = 2;
private final static int BLUE = 3;
private final static int WHITE = 4;
private final static int BLACK = 5;
private static int color = RED;
public static void click(Window window, TextView textView) {
color++;
StatusBarManager.getInstance().setStatusBarTextColor(window, false);
textView.setTextColor(Color.WHITE);
switch (color) {
case RED:
textView.setBackgroundColor(Color.RED);
if (!window.isFloating()) {
StatusBarManager.getInstance().setStatusBar(window, Color.parseColor("#dd0000"));
} else {
window.setBackgroundDrawable(new ColorDrawable(Color.parseColor("#dd0000")));
}
break;
case YELLOW:
textView.setBackgroundColor(Color.YELLOW);
StatusBarManager.getInstance().setStatusBarTextColor(window, true);
textView.setTextColor(Color.BLACK);
if (!window.isFloating()) {
StatusBarManager.getInstance().setStatusBar(window, Color.parseColor("#ffdd00"));
} else {
window.setBackgroundDrawable(new ColorDrawable(Color.parseColor("#ffdd00")));
}
break;
case GREEN:
textView.setBackgroundColor(Color.GREEN);
if (!window.isFloating()) {
StatusBarManager.getInstance().setStatusBar(window, Color.parseColor("#00dd00"));
} else {
window.setBackgroundDrawable(new ColorDrawable(Color.parseColor("#00dd00")));
}
break;
case BLUE:
textView.setBackgroundColor(Color.BLUE);
if (!window.isFloating()) {
StatusBarManager.getInstance().setStatusBar(window, Color.parseColor("#0000dd"));
} else {
window.setBackgroundDrawable(new ColorDrawable(Color.parseColor("#0000dd")));
}
break;
case WHITE:
textView.setBackgroundColor(Color.WHITE);
StatusBarManager.getInstance().setStatusBarTextColor(window, true);
textView.setTextColor(Color.BLACK);
if (!window.isFloating()) {
StatusBarManager.getInstance().setStatusBar(window, Color.parseColor("#ffffdd"));
} else {
window.setBackgroundDrawable(new ColorDrawable(Color.parseColor("#ffffdd")));
}
break;
case BLACK:
textView.setBackgroundColor(Color.BLACK);
if (!window.isFloating()) {
StatusBarManager.getInstance().setStatusBar(window, Color.parseColor("#333333"));
} else {
window.setBackgroundDrawable(new ColorDrawable(Color.parseColor("#333333")));
}
color = -1;
break;
}
}
public static void setImageViewBitmap(ImageView imageView) {
String path = Environment.getExternalStorageDirectory().getAbsolutePath();
path = path + "/1.jpg";
Bitmap bitmap = BitmapFactory.decodeFile(path);
imageView.setImageBitmap(bitmap);
}
}
2. DialogFragment实现StatusBar的沉浸式
- 方式一:
public class MutilDialogFragment extends DialogFragment {
public static MutilDialogFragment newInstance() {
return new MutilDialogFragment();
}
public static void showAdDialog(FragmentManager fragmentManager) {
FragmentTransaction ft = fragmentManager.beginTransaction();
MutilDialogFragment prev = (MutilDialogFragment) fragmentManager.findFragmentByTag("dialog");
if (prev != null) {
if (prev.isVisible()) {
prev.dismiss();
}
ft.remove(prev);
}
ft.addToBackStack(null);
MutilDialogFragment adDialogFragment = MutilDialogFragment.newInstance();
adDialogFragment.show(ft, "dialog");
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public void onStart() {
super.onStart();
DisplayMetrics dm = new DisplayMetrics();
if (getActivity() != null) {
getActivity().getWindowManager().getDefaultDisplay().getMetrics(dm);
}
Dialog dialog = getDialog();
if (dialog != null) {
Window window = dialog.getWindow();
if (window != null) {
//设置DialogFragment撑满屏幕
window.setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT);
}
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE);
//设置Dialog的Window样式或风格
StatusBarManager.getInstance().setDialogWindowStyle(getDialog().getWindow(), Color.parseColor("#dd0000"));
View view = LayoutInflater.from(getActivity()).inflate(R.layout.activity_text, container);
final TextView textView = (TextView) view.findViewById(R.id.image);
textView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ViewHelperUtils.click(getDialog().getWindow(), textView);
}
});
return view;
}
}
- 方式二:
public class ImageDialogFragment extends DialogFragment {
public static ImageDialogFragment newInstance() {
return new ImageDialogFragment();
}
public static void showAdDialog(FragmentManager fragmentManager) {
FragmentTransaction ft = fragmentManager.beginTransaction();
ImageDialogFragment prev = (ImageDialogFragment) fragmentManager.findFragmentByTag("dialog");
if (prev != null) {
if (prev.isVisible()) {
prev.dismiss();
}
ft.remove(prev);
}
ft.addToBackStack(null);
ImageDialogFragment adDialogFragment = ImageDialogFragment.newInstance();
adDialogFragment.show(ft, "dialog");
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public void onStart() {
super.onStart();
DisplayMetrics dm = new DisplayMetrics();
if (getActivity() != null) {
getActivity().getWindowManager().getDefaultDisplay().getMetrics(dm);
}
Dialog dialog = getDialog();
if (dialog != null) {
Window window = dialog.getWindow();
if (window != null) {
window.setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT);
}
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE);
StatusBarManager.getInstance().setDialogWindowStyle2(getDialog().getWindow());
View view = inflater.inflate(R.layout.common_image, container, false);
ImageView imageView = (ImageView) view.findViewById(R.id.second_image);
ViewHelperUtils.setImageViewBitmap(imageView);
return view;
}
}
3. Window实现StatusBar的沉浸式
- 方式一:
public void windowMutil(View view) {
final Window window = getWindow();
StatusBarManager.getInstance().setStatusBar(window, Color.parseColor("#dd0000"));
View v = LayoutInflater.from(getApplicationContext()).inflate(R.layout.activity_text2, null);
final TextView textView = (TextView) v.findViewById(R.id.text);
textView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ViewHelperUtils.click(window, textView);
}
});
StatusBarManager.getInstance().setWindowManagerStyle(window, v, false);
}
- 方式二:
public void windowImage(View view) {
View v = LayoutInflater.from(getApplicationContext()).inflate(R.layout.common_image, null);
ImageView imageView = (ImageView) v.findViewById(R.id.second_image);
ViewHelperUtils.setImageViewBitmap(imageView);
StatusBarManager.getInstance().setWindowManagerStyle(getWindow(), v, true);
}