相較於 iOS,安卓在 Q 以前並無原生支持護眼模式,因此咱們得本身實現一套。java
其實網上代碼也挺多的,甚至有些公司的產品就是這個功能。app
先來說下實現的思路,不想先聽思路的能夠直接跳到代碼那塊,代碼也不難。ide
Window
上覆蓋一個 View
,作到跨 App 及狀態欄和導航欄總體覆蓋建立一個 EyeCareService
,該 Service 用來添加 Window 上的濾光層ui
class EyeCareService : Service() {
private lateinit var windowManager: WindowManager
private lateinit var coverLayout: FrameLayout
override fun onBind(intent: Intent?): IBinder? {
return null
}
override fun onCreate() {
super.onCreate()
windowManager = getSystemService(Context.WINDOW_SERVICE) as WindowManager
val params = WindowManager.LayoutParams().apply {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
this.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY or
WindowManager.LayoutParams.TYPE_STATUS_BAR
} else {
this.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY
}
this.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE or
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS or
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN or
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
this.format = PixelFormat.TRANSLUCENT
}
windowManager.defaultDisplay.apply {
params.gravity = Gravity.START or Gravity.TOP
val point = Point()
this.getRealSize(point)
params.width = point.x
params.height = point.y
}
coverLayout = FrameLayout(this)
coverLayout.setBackgroundColor(Utils.getColor(30))
windowManager.addView(coverLayout, params)
}
override fun onDestroy() {
windowManager.removeViewImmediate(coverLayout)
super.onDestroy()
}
}
複製代碼
濾光層設置獲取顏色方法的方法,通常傳入 30 便可this
/** * 過濾藍光 * * @param blueFilterPercent 藍光過濾比例[10-80] */
public static @ColorInt
int getColor(int blueFilterPercent) {
int realFilter = blueFilterPercent;
if (realFilter < 10) {
realFilter = 10;
} else if (realFilter > 80) {
realFilter = 80;
}
int a = (int) (realFilter / 80f * 180);
int r = (int) (200 - (realFilter / 80f) * 190);
int g = (int) (180 - (realFilter / 80f) * 170);
int b = (int) (60 - realFilter / 80f * 60);
return Color.argb(a, r, g, b);
}
複製代碼
activity 中調用啓動方法spa
private fun openEyeCareMode() {
if (Build.VERSION.SDK_INT >= 23) {
if (Settings.canDrawOverlays(this)) { //有懸浮窗權限開啓服務綁定 綁定權限
val intent = Intent(this, EyeCareService::class.java)
startService(intent)
} else { //沒有懸浮窗權限,去開啓懸浮窗權限
try {
val intent = Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION)
startActivityForResult(intent, OVERLAY_PERMISSION_REQ_CODE)
} catch (e: Exception) {
e.printStackTrace()
}
}
} else { //默認有懸浮窗權限 可是 華爲, 小米,oppo等手機會有本身的一套Android6.0如下 會有本身的一套懸浮窗權限管理 也須要作適配
val intent = Intent(this, EyeCareService::class.java)
startService(intent)
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == OVERLAY_PERMISSION_REQ_CODE) {
if (Build.VERSION.SDK_INT >= 23) {
if (!Settings.canDrawOverlays(this)) {
//權限授予失敗,沒法開啓懸浮窗
return
} else {
//權限授予成功
}//有懸浮窗權限開啓服務綁定 綁定權限
}
val intent = Intent(this, EyeCareService::class.java)
startService(intent)
}
}
複製代碼
剩下一些考慮點,在這我就不貼代碼了,稍微講下code