@@ -31,7 +31,6 @@ import androidx.compose.runtime.Composable
3131import androidx.compose.runtime.CompositionLocalProvider
3232import androidx.compose.runtime.getValue
3333import androidx.compose.runtime.key
34- import androidx.compose.runtime.mutableStateMapOf
3534import androidx.compose.runtime.remember
3635import androidx.compose.runtime.rememberUpdatedState
3736import androidx.compose.ui.Alignment
@@ -56,6 +55,8 @@ import com.movtery.layer_controller.observable.ObservableButtonStyle
5655import com.movtery.layer_controller.observable.ObservableControlLayer
5756import com.movtery.layer_controller.observable.ObservableControlLayout
5857import com.movtery.layer_controller.observable.ObservableWidget
58+ import com.movtery.layer_controller.observable.TouchProcessor
59+ import com.movtery.layer_controller.observable.TouchSession
5960import com.movtery.layer_controller.utils.getWidgetPosition
6061
6162/* *
@@ -143,7 +144,6 @@ private fun BoxWithConstraintsScope.BaseControlBoxLayout(
143144 val reversedLayers = remember(layers) { layers.reversed() }
144145 val styles by observedLayout.styles.collectAsStateWithLifecycle()
145146
146- val allActiveWidgets = remember { mutableStateMapOf<PointerId , List <ObservableWidget >>() }
147147 val currentCheckOccupiedPointers by rememberUpdatedState(checkOccupiedPointers)
148148 val currentIsCursorGrabbing by rememberUpdatedState(isCursorGrabbing)
149149 val currentHideLayerWhen by rememberUpdatedState(hideLayerWhen)
@@ -158,6 +158,14 @@ private fun BoxWithConstraintsScope.BaseControlBoxLayout(
158158 }
159159 }
160160
161+ // 触控管线
162+ val touchSession = remember { TouchSession () }
163+ val touchProcessor = remember(screenSize) {
164+ TouchProcessor (eventHandler) { widget ->
165+ getWidgetPosition(widget, widget.internalRenderSize, screenSize)
166+ }
167+ }
168+
161169 Box (
162170 modifier = modifier
163171 .pointerInput(reversedLayers, hideLayerWhen) {
@@ -166,140 +174,36 @@ private fun BoxWithConstraintsScope.BaseControlBoxLayout(
166174 val event = awaitPointerEvent(pass = PointerEventPass .Initial )
167175
168176 event.changes.forEach { change ->
169- val position = change.position
170177 val pointerId = change.id
171- val isPressed = change.pressed
172-
173- // 抬起时,总是尝试释放该指针下活跃的按钮
174- // 避免子级占用了指针后,导致按钮状态无法被释放
175- if (! isPressed) {
176- allActiveWidgets.remove(pointerId)?.forEach { widget ->
178+ // 手指抬起,清理该指针所有状态
179+ if (! change.pressed) {
180+ touchSession.endPointer(pointerId).forEach { widget ->
181+ // 释放该指针事件
177182 widget.onReleaseEvent(eventHandler, reversedLayers)
178183 }
179184 return @forEach
180185 }
181186
182- if (
183- change.isConsumed ||
184- // 不处理被子级占用的指针
185- currentCheckOccupiedPointers(pointerId)
186- ) {
187- return @forEach
187+ if (change.isConsumed || currentCheckOccupiedPointers(pointerId)) {
188+ return @forEach // 跳过已消费或被占用的指针
188189 }
189190
190- // 在可见控件层中,收集所有可见的按钮
191- val visibleWidgets: List <ObservableWidget > = layers // 使用原始控件层顺序,保证触摸逻辑正常
192- .filter { layer ->
193- checkLayerVisibility(
194- layer = layer,
195- hideLayerWhen = currentHideLayerWhen,
196- isUsingJoystick = isUsingJoystick,
197- isCursorGrabbing = currentIsCursorGrabbing,
198- visibilityType = layer.visibilityType
199- )
200- }
201- .flatMap { layer ->
202- // 顶向下的顺序影响控件层的处理优先级
203- layer.normalButtons.value.reversed()
204- }
205-
206- // 查找当前指针在哪些按钮上
207- val targetWidgets = visibleWidgets
208- .filter { widget ->
209- if (! widget.canTouch()) return @filter false
210-
211- if (! checkVisibility(currentIsCursorGrabbing, widget.onCheckVisibilityType())) {
212- // 隐藏了,不响应事件
213- return @filter false
214- }
215-
216- val size = widget.internalRenderSize
217- val offset = getWidgetPosition(widget, size, screenSize)
218-
219- val x = position.x
220- val y = position.y
221- x >= offset.x && x <= offset.x + size.width &&
222- y >= offset.y && y <= offset.y + size.height
223- }.let { list ->
224- if (list.isEmpty()) return @let list
225-
226- val firstDeepWidget = list.firstOrNull { it.supportsDeepTouchDetection() }
227-
228- when {
229- firstDeepWidget == null -> list
230- else -> {
231- val topIndex = list.indexOf(firstDeepWidget)
232- list.subList(0 , topIndex + 1 ).filter { widget ->
233- ! widget.canProcess()
234- }
235- }
236- }
237- }
238-
239- var activeWidgets = allActiveWidgets[pointerId] ? : emptyList()
240-
241- // 检查是否移出边界
242- if (activeWidgets.isNotEmpty()) {
243- val backInBounds = mutableListOf<ObservableWidget >()
244- val releasedWidgets = mutableListOf<ObservableWidget >()
245- for (widget in activeWidgets) {
246- // 检查组件是否可以响应移除边界即松开
247- if (! widget.isReleaseOnOutOfBounds()) continue
248-
249- val size = widget.internalRenderSize
250- val offset = getWidgetPosition(widget, size, screenSize)
251- val isOutOfBounds = position.x !in offset.x.. (offset.x + size.width) ||
252- position.y !in offset.y.. (offset.y + size.height)
253-
254- if (isOutOfBounds) {
255- widget.onReleaseEvent(eventHandler, reversedLayers)
256- releasedWidgets.add(widget)
257- } else {
258- backInBounds.add(widget)
259- }
260- }
261- // fix: 移出边界时应移出组,否则滑动回已释放的按钮无法再次触发
262- if (releasedWidgets.isNotEmpty()) {
263- activeWidgets = activeWidgets - releasedWidgets
264- allActiveWidgets[pointerId] = activeWidgets
265- }
266- // fix: 应该在抬起事件全部处理完成后再处理 #941
267- if (backInBounds.isNotEmpty()) {
268- for (widget in backInBounds) {
269- widget.onPointerBackInBounds(eventHandler, reversedLayers)
270- }
271- }
272- }
273-
274- when {
275- targetWidgets.isEmpty() -> {}
276- else -> {
277- for (targetWidget in targetWidgets) {
278- if (targetWidget.canProcess()) {
279- return @forEach // 拒绝处理该事件
280- }
281-
282- targetWidget.onTouchEvent(
283- eventHandler = eventHandler,
284- allLayers = reversedLayers,
285- change = change,
286- activeWidgets = activeWidgets,
287- addThis = {
288- allActiveWidgets[pointerId] = activeWidgets + listOf (targetWidget)
289- },
290- consumeEvent = { value ->
291- if (value) {
292- change.consume()
293- } else {
294- // 将指针标记为仅接受滑动处理
295- // 期望子级不对点击事件等进行处理
296- markPointerAsMoveOnly(pointerId)
297- }
298- }
299- )
300- }
301- }
302- }
191+ // 收集可见控件
192+ val visibleWidgets = collectVisibleWidgets(
193+ layers = layers,
194+ hideLayerWhen = currentHideLayerWhen,
195+ isUsingJoystick = isUsingJoystick,
196+ isCursorGrabbing = currentIsCursorGrabbing,
197+ )
198+
199+ touchProcessor.processFrame(
200+ session = touchSession,
201+ change = change,
202+ visibleWidgets = visibleWidgets,
203+ allLayers = reversedLayers,
204+ consumeEvent = { it.consume() },
205+ markPointerAsMoveOnly = markPointerAsMoveOnly,
206+ )
303207 }
304208 }
305209 }
@@ -421,6 +325,38 @@ private fun ControlsRendererLayer(
421325 }
422326}
423327
328+ /* *
329+ * 收集所有可见控件层中的可触控控件
330+ * 只做图层可见性、控件可见类型检查,命中和深度检测由 [TouchProcessor] 提供
331+ */
332+ private fun collectVisibleWidgets (
333+ layers : List <ObservableControlLayer >,
334+ hideLayerWhen : HideLayerWhen ,
335+ isUsingJoystick : Boolean ,
336+ isCursorGrabbing : Boolean ,
337+ ): List <ObservableWidget > {
338+ return layers
339+ .filter { layer ->
340+ checkLayerVisibility(
341+ layer = layer,
342+ hideLayerWhen = hideLayerWhen,
343+ isUsingJoystick = isUsingJoystick,
344+ isCursorGrabbing = isCursorGrabbing,
345+ visibilityType = layer.visibilityType,
346+ )
347+ }
348+ .flatMap { layer ->
349+ // 反转,从顶到底
350+ layer.normalButtons.value.reversed()
351+ }
352+ .filter { widget ->
353+ widget.canTouch() && checkVisibility(
354+ isCursorGrabbing = isCursorGrabbing,
355+ visibilityType = widget.onCheckVisibilityType()
356+ )
357+ }
358+ }
359+
424360private fun checkLayerVisibility (
425361 layer : ObservableControlLayer ,
426362 hideLayerWhen : HideLayerWhen ,
0 commit comments