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

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的实现

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值