diff options
| author | 2025-03-12 04:03:39 -0700 | |
|---|---|---|
| committer | 2025-03-12 04:03:39 -0700 | |
| commit | 2ca8bb2e6a19e4fba6984a3aa1cc431feee0941c (patch) | |
| tree | fd4f879959f0e89b69d85a2a258fc1101bf61ca2 | |
| parent | 4f7b6c2494edbfcad7a75beb488e8ac92ac4f7a4 (diff) | |
| parent | f4a86dd4e4be54c6552fc76990dd7d50d463fe06 (diff) | |
Merge "Add NestedDraggable.Controller.autoStopNestedDrags" into main
| -rw-r--r-- | packages/SystemUI/compose/core/src/com/android/compose/gesture/NestedDraggable.kt | 19 | ||||
| -rw-r--r-- | packages/SystemUI/compose/core/tests/src/com/android/compose/gesture/NestedDraggableTest.kt | 36 | 
2 files changed, 53 insertions, 2 deletions
| diff --git a/packages/SystemUI/compose/core/src/com/android/compose/gesture/NestedDraggable.kt b/packages/SystemUI/compose/core/src/com/android/compose/gesture/NestedDraggable.kt index 80cbbea7659f..2ea9c487c27c 100644 --- a/packages/SystemUI/compose/core/src/com/android/compose/gesture/NestedDraggable.kt +++ b/packages/SystemUI/compose/core/src/com/android/compose/gesture/NestedDraggable.kt @@ -112,6 +112,14 @@ interface NestedDraggable {      interface Controller {          /** +         * Whether drags that were started from nested scrolls should be automatically +         * [stopped][onDragStopped] as soon as they don't consume the entire `delta` passed to +         * [onDrag]. +         */ +        val autoStopNestedDrags: Boolean +            get() = false + +        /**           * Drag by [delta] pixels.           *           * @return the consumed [delta]. Any non-consumed delta will be dispatched to the next @@ -609,8 +617,15 @@ private class NestedDraggableNode(      }      private fun scrollWithOverscroll(controller: NestedScrollController, offset: Offset): Offset { -        return scrollWithOverscroll(offset) { -            controller.controller.onDrag(it.toFloat()).toOffset() +        return scrollWithOverscroll(offset) { delta -> +            val available = delta.toFloat() +            val consumed = controller.controller.onDrag(available) +            if (controller.controller.autoStopNestedDrags && consumed != available) { +                controller.ensureOnDragStoppedIsCalled() +                this.nestedScrollController = null +            } + +            consumed.toOffset()          }      } diff --git a/packages/SystemUI/compose/core/tests/src/com/android/compose/gesture/NestedDraggableTest.kt b/packages/SystemUI/compose/core/tests/src/com/android/compose/gesture/NestedDraggableTest.kt index a03d769c9c36..b247993de4e4 100644 --- a/packages/SystemUI/compose/core/tests/src/com/android/compose/gesture/NestedDraggableTest.kt +++ b/packages/SystemUI/compose/core/tests/src/com/android/compose/gesture/NestedDraggableTest.kt @@ -1000,6 +1000,39 @@ class NestedDraggableTest(override val orientation: Orientation) : OrientationAw          assertThat(draggable.onDragStartedCalled).isTrue()      } +    @Test +    fun autoStopNestedDrags() { +        var consumeScrolls by mutableStateOf(true) +        val draggable = +            TestDraggable(autoStopNestedDrags = true, onDrag = { if (consumeScrolls) it else 0f }) + +        val touchSlop = +            rule.setContentWithTouchSlop { +                Box( +                    Modifier.fillMaxSize() +                        .nestedDraggable(draggable, orientation) +                        .scrollable(rememberScrollableState { 0f }, orientation) +                ) +            } + +        rule.onRoot().performTouchInput { +            down(center) +            moveBy((touchSlop + 1f).toOffset()) +        } + +        assertThat(draggable.onDragStartedCalled).isTrue() +        assertThat(draggable.onDragStoppedCalled).isFalse() + +        rule.onRoot().performTouchInput { moveBy(50f.toOffset()) } + +        assertThat(draggable.onDragStoppedCalled).isFalse() + +        consumeScrolls = false +        rule.onRoot().performTouchInput { moveBy(1f.toOffset()) } + +        assertThat(draggable.onDragStoppedCalled).isTrue() +    } +      private fun ComposeContentTestRule.setContentWithTouchSlop(          content: @Composable () -> Unit      ): Float { @@ -1027,6 +1060,7 @@ class NestedDraggableTest(override val orientation: Orientation) : OrientationAw              },          private val shouldConsumeNestedPostScroll: (Float) -> Boolean = { true },          private val shouldConsumeNestedPreScroll: (Float) -> Boolean = { false }, +        private val autoStopNestedDrags: Boolean = false,      ) : NestedDraggable {          var shouldStartDrag = true          var onDragStartedCalled = false @@ -1056,6 +1090,8 @@ class NestedDraggableTest(override val orientation: Orientation) : OrientationAw              onDragStarted.invoke(position, sign)              return object : NestedDraggable.Controller { +                override val autoStopNestedDrags: Boolean = this@TestDraggable.autoStopNestedDrags +                  override fun onDrag(delta: Float): Float {                      onDragCalled = true                      onDragDelta += delta |