android沉浸式状态栏StatusBar在不同Window下的实现

来源:互联网 发布:免费网店推广软件 编辑:程序博客网 时间:2024/06/05 23:44

android沉浸式状态栏StatusBar在不同Window下的实现

StatusBar沉浸式的2种实现方式

对于沉浸式状态栏的实现,我觉得有两种实现方式

一是:将状态栏的颜色和状态栏下面的View颜色保持一致或相近。如图:

image

二是:将View充满全屏,状态栏覆盖在View上,将状态栏设置为透明色

image

StatusBar沉浸式实现的真相

我们使用Android Studio的提供的截图工具Layout Inspector工具分析可以知道,实际上显示时间、信号等SystemBar是系统级别的一个Window(悬浮窗)。而StatusBar是SystemBar下面的View,是DecorView的一部分。我们通常设置StatusBar的颜色其实就是给SystemBar覆盖的StatusBar设置一个背景色。

LayoutInspetor工具的截图:

image

由上图可知,StatusBar是DecorView的一部分,是一个View设置了背景色,没有系统的时间、信号等信息。

所以我们所设置状态栏的颜色,就是设置DecorView中的StatusBar的View的颜色。

image

上图说明: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);}

Github地址:android沉浸式状态栏StatusBar在多种Window的实现

原创粉丝点击