调整APP亮度,并且最高不高于系统亮度实现方案

项目新需求,app亮度进行单独调节,但是调整的最大亮度不能高于系统亮度,接到需求之后,就在考虑实现方案,大致想到了三种方案

  • 直接调整系统亮度

在app中直接调整系统亮度,保存当前系统亮度,然后在activity生命周期中监听回到桌面(这里可在Application中registerActivityLifecycleCallbacks来实现),回到桌面之后调整回原来的系统亮度,切回app的时候再设置成app本身设置的系统亮度。

  • 在DecorView外层添加view

对再BaseActivity中获取当前window的getDecorView,然后在这个ViewGroup上添加一个ImageView,使用viewGroup的bringChildToFront(View view)方法将添加的ImageView设置到最外层,然后对这个ImageView 进行背景的透明度调节,核心代码如下

            mNightView = new ImageView(this);
            ViewGroup root = (ViewGroup)getWindow().getDecorView();
            Ln.d("添加view  view = " + root.getChildCount());
            root.addView(mNightView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
            root.bringChildToFront(mNightView);
  • 直接调节当前窗口

直接在BaseActivity中获取窗口window,然后获取window的WindowManager.LayoutParams,对其screenBrightness属性进行调节,这个是大多数推荐的对单个app亮度进行调节的方式,我们今天主要讲述的重点也就是这个

首先我们来分析下为什么我们选择第三种,而不选择前面两种

首先来看第一种,第一种方案,貌似是一个很可行的方案,很容易满足我们的需求,最大亮度只能是当前系统的最大亮度,而且一调整整个app都会调整,那为什么我们会不选择呢?因为这里有一个设置系统亮度的步骤,我们如果想要设置系统的亮度,就涉及到一个问题,权限,android系统对非系统签名的应用,在更改系统设置的时候是需要权限的,这一点在6.0之后尤为严格,所以试想,当我们采用此方案的话,那么在设置app亮度的时候首先要去请求权限,这时候就会出现弹框,这一步就已经很让用户烦躁了,就算用户没有厌烦情绪万一用户点击了拒绝,那我们这个功能岂不就会失效了,因此这绝非一个好的实现方案

其次,我们来看第二种,这种方案我做过测试,如果我们只对主界面进行调整,那么这种方案也是可以满足我们的需求的,但是这里也有有个漏洞,就是弹框,不管是Dialog,Popupwindow,DialogFragment,还是BottomSheetDialogFragment,这些弹框都是覆盖在activity之上的,也就是说我们添加的那个ImageView是盖不住这些弹框的,因此,当我们调整亮度到很低的时候,如果有弹框出来就会直接弹出高亮度的弹框,这显然不是一个好的体验,因此也pass了

接下来我们来说这篇文章的重点

首先我们需要获取当前系统的亮度

private int getScreenBrightness(Context context) {
        ContentResolver contentResolver = context.getContentResolver();
        int defVal = 127;
        return Settings.System.getInt(contentResolver,
                Settings.System.SCREEN_BRIGHTNESS, defVal);
    }

获取到系统得最大亮度,这里我们一定要获取最大亮度而不是直接设置为255,尽管官方说的系统最大亮度是255,但是我发现小米手机的亮度值是远远大于这个值的(小米8上面最大是1023)

private int getBrightnessMax() {
        try {
            Resources system = Resources.getSystem();
            int resId = system.getIdentifier("config_screenBrightnessSettingMaximum", "integer", "android");
            if (resId != 0) {
                return system.getInteger(resId);
            }
        } catch (Exception ignore) {
        }
        return 255;
    }
        /**
         * The screen backlight brightness between 0 and 255.
         */
        public static final String SCREEN_BRIGHTNESS = "screen_brightness";

设置app亮度

private void setAppScreenBrightness(int birghtessValue) {
        float systemBright = getScreenBrightness(this);
        Window window = getWindow();
        WindowManager.LayoutParams lp = window.getAttributes();
        float max = getBrightnessMax();
        float ratio = systemBright / max;//系统的最大亮度就是当前window的最大亮度
        float setbright = birghtessValue / 255.0f;
        /**
         * 当前window的亮度值应当是系统的最大亮度值和当前window真实亮度值相乘,
         * 标示不能超过系统亮度,setbright 最大为1
         */
        lp.screenBrightness = setbright * ratio;
        window.setAttributes(lp);
    }

这里还要注意一点,就是你的进度条最大进度设置为255,如果进度太小的话 ,会出现当调整完系统亮度后,回到app的时候会出现明显变暗的情况,我当初最大设置的是100,后面修改最大值之后就好了。

另外我们还需要监听下系统亮度是否有变化,当有变化的时候我们也要同步修改app的亮度
监听方法如下

 * 监听屏幕亮度变化
     */
    private ContentObserver mBrightnessObserver = new ContentObserver(new Handler()) {
        @Override
        public void onChange(boolean selfChange) {
            updateBright();
        }
    };

我们只需要在BaseActivity的onResume()方法中注册,在onDestory()中取消注册就好了

 @Override
    protected void onResume() {
        super.onResume();
                getContentResolver().registerContentObserver(
                Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS), true,
                mBrightnessObserver);
    }
@Override
    protected void onDestroy() {
        super.onDestroy();
        getContentResolver().unregisterContentObserver(
                mBrightnessObserver);
    }

如果错误,请指正~
更多关于技术相关的内容请关注博主公众号–迷途程序猿
迷途程序猿

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章