再回首沉浸式状态栏以及魅族手机等系统问题解决

        上次写过一篇解决沉浸式状态栏问题的文章,不过当时仅仅是为了解决两个问题,没有过多理解过沉浸式,以至于每次发开需要沉浸式都需要网上搜索半天,然后拷贝代码过来,修改修改就得了,今天正好静下心来好好思考了一下沉浸式。

        页面做成沉浸式的思路有两个:

       第一.就是直接修改状态栏的颜色,需要什么颜色就将状态栏的颜色改成什么颜色,就这么简单,没了。纯白色沉浸式设置代码如下:

      

/**
     * 设置沉浸式状态栏
     */
    public static void immersiveNotificationBar(Activity activity) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {//字体颜色改为黑色,非白色沉浸式状态栏不需要设置
            activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
        }
        immersiveNotificationBar(activity, 255);
    }

    /**
     * 设置沉浸式状态栏
     */
    public static void immersiveNotificationBar(Activity activity, int alpha) {
        String brand = Build.BRAND;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            Window window = activity.getWindow();
            window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {//解决华为手机等状态栏上面有一个蒙层问题
                try {
                    Class decorViewClazz = Class.forName("com.android.internal.policy.DecorView");
                    Field field = decorViewClazz.getDeclaredField("mSemiTransparentStatusBarColor");
                    field.setAccessible(true);
                    field.setInt(window.getDecorView(), Color.TRANSPARENT);  //改为透明
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (NoSuchFieldException e) {
                    e.printStackTrace();
                }
            }
            if ("vivo".equalsIgnoreCase(brand) || "OPPO".equals(brand)) {//oppo和vivo手机状态栏最好不要显示为纯白色,官方未给出改变字体颜色为黑色方法
                window.setStatusBarColor(Color.argb(alpha, 208, 208, 208));
            } else {
                window.setStatusBarColor(Color.argb(alpha, 255, 255, 255));
            }
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
            ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
            int count = decorView.getChildCount();
            if (count > 0 && null != decorView.getChildAt(count - 1)) {
                decorView.getChildAt(count - 1).setBackgroundColor(calculateStatusColor(Color.WHITE, 30));
            } else {
                View statusView = createStatusBarView(activity, Color.WHITE, 30);
                decorView.addView(statusView);
            }
            setRootView(activity);
        }
    }

    private static View createStatusBarView(Activity activity, @ColorInt int color, int alpha) {
        View statusBarView = new View(activity);
        LinearLayout.LayoutParams params =
                new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getStarusBarHeight(activity));
        statusBarView.setLayoutParams(params);
        statusBarView.setBackgroundColor(calculateStatusColor(color, alpha));
        return statusBarView;
    }

    private static void setRootView(Activity activity) {
        ViewGroup rootView = (ViewGroup) ((ViewGroup) activity.findViewById(android.R.id.content)).getChildAt(0);
        rootView.setFitsSystemWindows(true);
        rootView.setClipToPadding(true);
    }

    private static int calculateStatusColor(@ColorInt int color, int alpha) {
        float a = 1 - alpha / 255f;
        int red = color >> 16 & 0xff;
        int green = color >> 8 & 0xff;
        int blue = color & 0xff;
        red = (int) (red * a + 0.5);
        green = (int) (green * a + 0.5);
        blue = (int) (blue * a + 0.5);
        return 0xff << 24 | red << 16 | green << 8 | blue;
    }

    public static int getStarusBarHeight(Context context) {
        int statusBarHeight1 = -1;
        int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
        if (resourceId > 0) {
            statusBarHeight1 = context.getResources().getDimensionPixelSize(resourceId);
        }
        return statusBarHeight1;
    }

        代码复制过去就可以了,然后将setStatusBarColor里的颜色值改成自己的就可了,很简单。

       第二种方法,就是将状态栏的颜色改为透明,然后页面设置为全屏显示,自己页面顶部预留一个view来当做状态栏。这个呢,灵活性高,可控性也好,相对于第一种来说适用范围更广,可以说就是我自己想让状态栏显示什么就显示什么,当然了仔细想想其实这是一种假象。具体过程分为三个步骤:

     1)页面设置为全屏且显示状态栏,状态栏为透明

/**
     * 通过设置全屏,设置状态栏透明
     *
     * @param activity
     */
    private void fullScreen(Activity activity) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                //5.x开始需要把颜色设置透明,否则导航栏会呈现系统默认的浅灰色
                Window window = activity.getWindow();
                View decorView = window.getDecorView();
                //两个 flag 要结合使用,表示让应用的主体内容占用系统状态栏的空间
                int option = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                        | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                    option = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                            | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                            | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
                }
                window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
                decorView.setSystemUiVisibility(option);
                window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
                window.setStatusBarColor(Color.TRANSPARENT);
                //导航栏颜色也可以正常设置
//                window.setNavigationBarColor(Color.TRANSPARENT);
            } else {
                Window window = activity.getWindow();
                WindowManager.LayoutParams attributes = window.getAttributes();
                int flagTranslucentStatus = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
                int flagTranslucentNavigation = WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
                attributes.flags |= flagTranslucentStatus;
//                attributes.flags |= flagTranslucentNavigation;
                window.setAttributes(attributes);
            }
        }

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {//解决华为手机等状态栏上面有一个蒙层问题
            try {
                Class decorViewClazz = Class.forName("com.android.internal.policy.DecorView");
                Field field = decorViewClazz.getDeclaredField("mSemiTransparentStatusBarColor");
                field.setAccessible(true);
                field.setInt(getWindow().getDecorView(), Color.TRANSPARENT);  //改为透明
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            }
        }
    }

        2)设置布局中的顶部view高度为状态栏高度(或者自己想着顶部直接弄成顶天的图片也可以)

        3)设置顶部view的颜色,随意修改达到沉浸式,甚至可以添加图片都无所谓

好了,沉浸式状态栏问题就这样基本解决了,再回头想想,真的没什么。不过最让人头疼的应该是国产系统的适配问题解决,沉浸式中最难的应该就是属于白色沉浸式问题,状态栏颜色变成深色问题。下面我们来解决魅族手机状态栏字体颜色问题。

问题如下:

        Activity+四个Fragment,Fragment切换时切换状态栏颜色没问题,但是在其中一个Fragment中跳转另一个Activity,然后再回来的时候设置黑色状态栏的那个Fragment就失效了,请问是怎么回事?每次点击切换Fragment的时候都有设置状态栏颜色。

       很不幸我也遇到了这个问题,我们分析分析为什么?魅族手机牛逼的地方在于他会自动读取状态栏下面view的颜色值,然后根据读取到的颜色值来自动设置字体的颜色,尼玛,这就完全不可控了啊!!!!我觉得应该不止魅族系统这样,奥,对了,使用魅族官网的设置状态栏字体颜色的代码也照样没卵用。那么我们怎么办?欺骗系统,我们可以欺骗系统,怎么欺骗?就是当系统读取状态栏后面view的时候,我们提前手动设置view的颜色,等着读取完了我们再改成我们想要的颜色,这不就解决了!还是以需要状态栏字体为黑色为例(沉浸式状态栏设置方式为上面第二种方法):

    第一步:直接操作我们要显示的沉浸式view或者在view上面再覆盖一层也可以,我们就以上面再覆盖一层view为例吧,xml中view的颜色要设置为白色。

    重写window获取焦点的方法,当页面获取到焦点时我们将覆盖的view设置为透明颜色

@Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);
        if (hasFocus) {
            if (null == mView) {//mView就是状态栏或者上面覆盖的一层
                mView = findViewById(R.id.status_view);
                mView.post(new Runnable() {//为了解决初次进来状态栏字体颜色为白色
                    @Override
                    public void run() {
                        mView.setBackgroundColor(Color.TRANSPARENT);
                    }
                });
            } else {
                mView.setBackgroundColor(Color.TRANSPARENT);
            }
        }
    }

    第二步:就是当页面彻底不可见的时候我们再次将view的北京颜色设置为白色,当页面再次可见时扔会执行上面代码设置为透明

@Override
    protected void onStop() {
        super.onStop();
        if (null != mView) {
            mView.setBackgroundColor(Color.WHITE);
        }
    }

    这里需要说明为什么是在onstop中而不是onpause方法中设置,在onpause中设置会让用户看见白色的状态栏,所以用在onstop中设置。

    最后贴一张图(魅蓝note6)手机上的效果:

    再回首沉浸式状态栏以及魅族手机等系统问题解决_第1张图片

最后将github源码地址贴一下,欢迎star:  https://github.com/zhq217217/chenjinshi_statusbar

你可能感兴趣的:(工作记录)