android夜间模式实现方式

时间:2022-01-05 12:29:04

记得之前看小说,下了一个夜间模式用用,居然一大堆的广告,用的太不爽了,于是自己写一个用。其实原理很简单,就是添加一个带有黑色透明的悬浮窗而已。
说下实现步骤:
1、添加悬浮窗,需要用到WindowManager对象
2、如果要保证我们退出程序,也要保证夜间模式还是启动的状态,那么就需要用到Service
3、为了保证Service不被系统杀死,所以准备使用前台服务

看下服务类的代码

public class NightModeService extends Service {
    private LinearLayout mNightView;
    private LocalBinder mBind = new LocalBinder();
    public boolean isRunning = true;

    @Override
    public void onCreate() {
        super.onCreate();
        // 保护眼睛模式的核心代码
        WindowManager localWindowManager = (WindowManager) getApplication().getSystemService("window");
        WindowManager.LayoutParams localLayoutParams = new WindowManager.LayoutParams();
        this.mNightView = new LinearLayout(getApplicationContext());
        //不让悬浮窗获取焦点
        this.mNightView.setFocusable(false);
        this.mNightView.setFocusableInTouchMode(false);
        // this.mNightView.setBackgroundColor(Color.argb(153, 0, 8, 13));
        localLayoutParams.type = LayoutParams.TYPE_SYSTEM_OVERLAY;
        localLayoutParams.flags = LayoutParams.FLAG_LAYOUT_IN_SCREEN;
        //支持透明度
        localLayoutParams.format = PixelFormat.RGBA_8888;
        localLayoutParams.gravity = Gravity.CENTER;
        localLayoutParams.x = 0;
        localLayoutParams.y = 0;
        localLayoutParams.width = LayoutParams.MATCH_PARENT;
        localLayoutParams.height = LayoutParams.MATCH_PARENT;
        localWindowManager.addView(this.mNightView, localLayoutParams);
        // 将service作为前台服务
        NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        Notification notification = new Notification(R.drawable.ic_launcher, "夜间模式", System.currentTimeMillis());
        Intent intent = new Intent(this, MainActivity.class);
        PendingIntent pIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
        notification.setLatestEventInfo(this, "夜间模式", "开启", pIntent);
        notification.flags = Notification.FLAG_ONGOING_EVENT;// 常驻状态栏
        startForeground(1, notification);
    }

    @Override
    public IBinder onBind(Intent intent) {
        return mBind;
    }

    public class LocalBinder extends Binder {
        public NightModeService getService() {
            return NightModeService.this;
        }
    }

    public void setWindowColor(int color) {
        this.mNightView.setBackgroundColor(color);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        WindowManager localWindowManager = (WindowManager) getApplication().getSystemService("window");
        localWindowManager.removeView(mNightView);
    }
}

首先我们通过Context.getSystemService()方法获取WindowManager对象,
然后我们创建mNightView,别切设置他的焦点和LayoutParams属性,再通过WindowManager的addView()方法将我们创建的mNightView,添加进去,最后将Service通过startForeground()设为前台,保证不被系统杀死。

Activity中没有什么特别的方法,只是我继承了PreferenceActivity,可能这个Activity大家不是很熟悉,其实也没什么,很简单,找点资料就能解决,那就挑重点的说下吧。

判断当前的夜间模式有没有开启

    public static boolean isServiceRunning(Context mContext, String className) {

        boolean isRunning = false;
        ActivityManager activityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
        List<ActivityManager.RunningServiceInfo> serviceList = activityManager.getRunningServices(30);

        if (!(serviceList.size() > 0)) {
            return false;
        }

        for (int i = 0; i < serviceList.size(); i++) {
            if (serviceList.get(i).service.getClassName().equals(className) == true) {
                isRunning = true;
                break;
            }
        }
        return isRunning;
    }

这个其实是判断当前的Service是不是已经开启了,Service开启的话,那么这个夜间模式就是开启状态,后来想了一下,当时让我想复杂了,其实在只要在Service添加一个标记值就搞定了,不过我们可以学下一下这个方法,说不定以后还有用处。
这个方法也是获取到系统的服务ActivityManager,获取里面所有的服务,进行比对,就可以知道当前的服务是否在运行。

最后添加了一个颜色选择器,[ColorPickerPreference]] (https://github.com/attenzione/android-ColorPickerPreference)

看效果图:
android夜间模式实现方式

对了,小米手机许设置允许悬浮窗的权限,要不然看不到效果。

下载工程源码