Skip to content

Commit 4b57b68

Browse files
author
Ven
committed
feat: 步骤器改为协程调度
1 parent e576b94 commit 4b57b68

26 files changed

+921
-158
lines changed

assists/src/main/java/com/ven/assists/AssistsWindowLayout.kt

Lines changed: 49 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@ import android.view.Gravity
99
import android.view.LayoutInflater
1010
import android.view.MotionEvent
1111
import android.view.View
12+
import android.view.ViewTreeObserver
1213
import android.view.WindowManager
1314
import android.widget.FrameLayout
1415
import com.blankj.utilcode.util.BarUtils
16+
import com.blankj.utilcode.util.ScreenUtils
1517
import com.blankj.utilcode.util.SizeUtils
1618
import com.ven.assists.base.databinding.AssistsWindowLayoutWrapperBinding
1719

@@ -23,6 +25,9 @@ class AssistsWindowLayout @JvmOverloads constructor(
2325
var layoutWidth: Int = 0
2426
var downRawX = 0
2527
var downRawY = 0
28+
var closeClickListener: (() -> Boolean)? = null
29+
var minHeight = -1
30+
var minWidth = -1
2631

2732
private val onTouchScaleListener = object : OnTouchListener {
2833
override fun onTouch(v: View?, event: MotionEvent): Boolean {
@@ -36,15 +41,20 @@ class AssistsWindowLayout @JvmOverloads constructor(
3641
if (event.action == MotionEvent.ACTION_MOVE) {
3742
val width = layoutWidth + (downRawX - event.rawX.toInt())
3843
if (width > 0) {
39-
layoutParams.width = width
40-
layoutParams.x = event.rawX.toInt()
44+
if (minWidth == -1 || width >= minWidth) {
45+
layoutParams.width = width
46+
layoutParams.x = event.rawX.toInt()
47+
}
4148
}
4249

4350
val height = layoutHeight - (downRawY - event.rawY.toInt())
51+
4452
if (height > 0) {
45-
layoutParams.height = height
53+
if (minHeight == -1 || height >= minHeight) {
54+
layoutParams.height = height
55+
}
4656
}
47-
AssistsWindowManager.windowManager.updateViewLayout(this@AssistsWindowLayout, layoutParams)
57+
AssistsWindowManager.updateViewLayout(this@AssistsWindowLayout, layoutParams)
4858
return true
4959
}
5060

@@ -59,7 +69,7 @@ class AssistsWindowLayout @JvmOverloads constructor(
5969
if (event.action == MotionEvent.ACTION_MOVE) {
6070
layoutParams.x = event.rawX.toInt()
6171
layoutParams.y = event.rawY.toInt() - BarUtils.getStatusBarHeight()
62-
AssistsWindowManager.windowManager.updateViewLayout(this@AssistsWindowLayout, layoutParams)
72+
AssistsWindowManager.updateViewLayout(this@AssistsWindowLayout, layoutParams)
6373
return true
6474
}
6575

@@ -80,6 +90,11 @@ class AssistsWindowLayout @JvmOverloads constructor(
8090
assistsWindowLayoutWrapperBinding = AssistsWindowLayoutWrapperBinding.inflate(LayoutInflater.from(getContext()), this).apply {
8191
ivMove.setOnTouchListener(onTouchMoveListener)
8292
ivScale.setOnTouchListener(onTouchScaleListener)
93+
ivClose.setOnClickListener {
94+
val result = closeClickListener?.invoke()
95+
if (result == true) return@setOnClickListener
96+
AssistsWindowManager.removeView(this@AssistsWindowLayout)
97+
}
8398
}
8499

85100
layoutParams.flags = (WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
@@ -97,8 +112,8 @@ class AssistsWindowLayout @JvmOverloads constructor(
97112
layoutParams.alpha = 1f
98113
}
99114

100-
fun setOnCloseClickListener(onClickListener: OnClickListener) {
101-
assistsWindowLayoutWrapperBinding.ivClose.setOnClickListener(onClickListener)
115+
fun setOnCloseClickListener(closeClickListener: () -> Boolean) {
116+
this.closeClickListener = closeClickListener
102117
}
103118

104119
override fun onAttachedToWindow() {
@@ -113,14 +128,39 @@ class AssistsWindowLayout @JvmOverloads constructor(
113128
}
114129
}
115130

131+
fun setCenter() {
132+
if (measuredWidth > 0 && measuredHeight > 0) {
133+
val x = (ScreenUtils.getScreenWidth() - measuredWidth) / 2
134+
val y = (ScreenUtils.getScreenHeight() - BarUtils.getStatusBarHeight() - measuredHeight) / 2
135+
layoutParams.x = x
136+
layoutParams.y = y
137+
AssistsWindowManager.updateViewLayout(this@AssistsWindowLayout, layoutParams)
138+
} else {
139+
viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
140+
override fun onGlobalLayout() {
141+
if (measuredWidth > 0 && measuredHeight > 0) {
142+
val x = (ScreenUtils.getScreenWidth() - measuredWidth) / 2
143+
val y = (ScreenUtils.getScreenHeight() - BarUtils.getStatusBarHeight() - measuredHeight) / 2
144+
layoutParams.x = x
145+
layoutParams.y = y
146+
AssistsWindowManager.updateViewLayout(this@AssistsWindowLayout, layoutParams)
147+
viewTreeObserver.removeOnGlobalLayoutListener(this)
148+
}
149+
}
150+
151+
})
152+
}
153+
154+
}
155+
116156
/**
117157
* 切换至不可消费事件
118158
*/
119159
fun switchNotTouchable() {
120160
layoutParams.flags = (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or
121161
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE or
122162
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL)
123-
AssistsWindowManager.windowManager.updateViewLayout(this, layoutParams)
163+
AssistsWindowManager.updateViewLayout(this, layoutParams)
124164
}
125165

126166
/**
@@ -130,7 +170,7 @@ class AssistsWindowLayout @JvmOverloads constructor(
130170
layoutParams.flags = (WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH or
131171
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or
132172
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE)
133-
AssistsWindowManager.windowManager.updateViewLayout(this, layoutParams)
173+
AssistsWindowManager.updateViewLayout(this, layoutParams)
134174
}
135175

136176
}

assists/src/main/java/com/ven/assists/AssistsWindowManager.kt

Lines changed: 110 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,130 @@ package com.ven.assists
22

33
import android.accessibilityservice.AccessibilityService
44
import android.content.Context
5+
import android.graphics.PixelFormat
56
import android.util.DisplayMetrics
7+
import android.view.Gravity
8+
import android.view.View
9+
import android.view.ViewGroup
610
import android.view.WindowManager
11+
import androidx.core.view.isInvisible
12+
import java.util.Collections
713

814
object AssistsWindowManager {
9-
lateinit var windowManager: WindowManager
15+
private lateinit var windowManager: WindowManager
1016
private lateinit var mDisplayMetrics: DisplayMetrics
17+
private val viewList = Collections.synchronizedList(arrayListOf<ViewWrapper>())
1118
fun init(accessibilityService: AccessibilityService) {
1219
windowManager = accessibilityService.getSystemService(Context.WINDOW_SERVICE) as WindowManager
1320
mDisplayMetrics = DisplayMetrics()
1421
windowManager.defaultDisplay.getMetrics(mDisplayMetrics)
1522
}
1623

17-
fun addView(view: AssistsWindowLayout?) {
24+
fun createLayoutParams(): WindowManager.LayoutParams {
25+
val layoutParams = WindowManager.LayoutParams()
26+
layoutParams.flags = (WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
27+
or WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
28+
or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE)
29+
layoutParams.height = WindowManager.LayoutParams.MATCH_PARENT
30+
layoutParams.width = WindowManager.LayoutParams.MATCH_PARENT
31+
layoutParams.gravity = Gravity.START or Gravity.TOP
32+
layoutParams.format = PixelFormat.RGBA_8888
33+
//此处layoutParams.type不建议使用TYPE_TOAST,因为在一些版本较低的系统中会出现拖动异常的问题,虽然它不需要权限
34+
layoutParams.type = WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY
35+
//背景明暗度0~1,数值越大背景越暗,只有在flags设置了WindowManager.LayoutParams.FLAG_DIM_BEHIND 这个属性才会生效
36+
layoutParams.dimAmount = 0.0f
37+
//透明度0~1,数值越大越不透明
38+
layoutParams.alpha = 1f
39+
return layoutParams
40+
}
41+
42+
fun hideAll() {
43+
viewList.forEach {
44+
it.view.isInvisible = true
45+
if (it.view is AssistsWindowLayout) {
46+
it.view.switchNotTouchable()
47+
}
48+
}
49+
}
50+
51+
52+
fun addView(view: View?, params: ViewGroup.LayoutParams) {
1853
view ?: return
54+
viewList.forEach {
55+
it.view.isInvisible = true
56+
if (it.view is AssistsWindowLayout) {
57+
it.view.switchNotTouchable()
58+
}
59+
}
60+
61+
windowManager.addView(view, params)
62+
viewList.add(ViewWrapper(view, params))
63+
}
64+
65+
fun addAssistsWindowLayout(view: AssistsWindowLayout?) {
66+
view ?: return
67+
viewList.forEach {
68+
it.view.isInvisible = true
69+
if (it.view is AssistsWindowLayout) {
70+
it.view.switchNotTouchable()
71+
}
72+
}
73+
1974
windowManager.addView(view, view.layoutParams)
75+
viewList.add(ViewWrapper(view, view.layoutParams))
76+
}
77+
78+
fun removeView(view: View?) {
79+
view ?: return
80+
windowManager.removeView(view)
81+
for (viewWrapper in viewList) {
82+
if (viewWrapper.view == view) {
83+
viewList.remove(viewWrapper)
84+
break
85+
}
86+
}
87+
viewList.lastOrNull()?.let {
88+
it.view.isInvisible = false
89+
if (it.view is AssistsWindowLayout) {
90+
it.view.switchTouchable()
91+
}
92+
}
93+
}
94+
95+
fun updateViewLayout(view: View, params: ViewGroup.LayoutParams) {
96+
windowManager.updateViewLayout(view, params)
97+
}
98+
99+
/**
100+
* 切换至不可消费事件
101+
*/
102+
fun switchNotTouchableAll() {
103+
viewList.forEach {
104+
if (it.layoutParams is WindowManager.LayoutParams) {
105+
it.layoutParams.flags = (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or
106+
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE or
107+
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL)
108+
updateViewLayout(it.view, it.layoutParams)
109+
}
110+
}
111+
112+
}
113+
114+
/**
115+
* 切换至可消费事件
116+
*/
117+
fun switchTouchableAll() {
118+
119+
viewList.forEach {
120+
if (it.layoutParams is WindowManager.LayoutParams) {
121+
it.layoutParams.flags = (WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH or
122+
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or
123+
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE)
124+
updateViewLayout(it.view, it.layoutParams)
125+
}
126+
}
20127
}
21128

129+
class ViewWrapper(val view: View, val layoutParams: ViewGroup.LayoutParams)
22130

23131
}

assists/src/main/java/com/ven/assists/stepper/StepCollector.kt

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,32 +14,45 @@ class StepCollector(private val clazzName: String) {
1414
/**
1515
* 单次步骤
1616
* @param step 步骤序号
17+
* @param isRunCoroutineIO 是否在IO协程中执行
1718
* @param next 步骤逻辑接口
1819
*/
1920
fun next(
2021
step: Int,
22+
isRunCoroutineIO: Boolean = false,
2123
next: (stepOperator: StepOperator) -> Unit
2224
): StepCollector {
23-
stepOperatorMap[step] = StepOperator(clazzName, step, next = {
24-
next.invoke(it)
25-
true
26-
})
25+
nextLoop(
26+
step = step,
27+
loopMaxCount = 1,
28+
isRunCoroutineIO = isRunCoroutineIO,
29+
next = {
30+
next.invoke(it)
31+
true
32+
})
2733
return this
2834
}
2935

3036
/**
3137
* 循环步骤
3238
* @param step 步骤序号
33-
* @param loopDuration 循环时长
34-
* @param next 步骤逻辑接口,接口中需要返回[kotlin.Boolean],false继续循环,true终止循环
39+
* @param loopMaxCount 最大循环次数
40+
* @param isRunCoroutineIO 是否在IO协程中执行
41+
* @param next 步骤逻辑,需要返回[kotlin.Boolean],false继续循环,true终止循环
3542
*/
3643
fun nextLoop(
3744
step: Int,
38-
loopDuration: Long = 5000,
39-
loopInterval: Long = 250,
45+
loopMaxCount: Int = 5,
46+
isRunCoroutineIO: Boolean = false,
4047
next: (stepOperator: StepOperator) -> Boolean
4148
): StepCollector {
42-
stepOperatorMap[step] = StepOperator(clazzName, step, loopDuration = loopDuration, loopInterval = loopInterval, next)
49+
stepOperatorMap[step] = StepOperator(
50+
clazzName,
51+
step,
52+
loopMaxCount = loopMaxCount,
53+
isRunCoroutineIO = isRunCoroutineIO,
54+
next = next
55+
)
4356
return this
4457
}
4558

assists/src/main/java/com/ven/assists/stepper/StepManager.kt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ package com.ven.assists.stepper
22

33
import android.util.Log
44
import com.ven.assists.Assists
5+
import kotlinx.coroutines.CoroutineScope
6+
import kotlinx.coroutines.Dispatchers
7+
import kotlinx.coroutines.Job
8+
import kotlinx.coroutines.cancel
59

610
/**
711
* 步骤管理器
@@ -12,11 +16,22 @@ object StepManager {
1216
var stepListeners: ArrayList<StepListener> = arrayListOf()
1317

1418
private val stepCollector: HashMap<String, StepCollector> = hashMapOf()
19+
private var job = Job()
20+
var coroutine: CoroutineScope = CoroutineScope(job + Dispatchers.IO)
21+
private set
22+
get() {
23+
if (job.isCancelled || !job.isActive) {
24+
job = Job()
25+
field = CoroutineScope(job + Dispatchers.IO)
26+
}
27+
return field
28+
}
1529
var isStop = false
1630
set(value) {
1731
field = value
1832
if (field) {
1933
stepCollector.forEach { it.value.allStop() }
34+
coroutine.cancel()
2035
}
2136
}
2237

0 commit comments

Comments
 (0)