Loading packages/SystemUI/compose/core/src/com/android/compose/gesture/NestedDraggable.kt +17 −2 Original line number Diff line number Diff line Loading @@ -111,6 +111,14 @@ interface NestedDraggable { fun shouldConsumeNestedPreScroll(sign: Float): Boolean = false 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. * Loading Loading @@ -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() } } Loading packages/SystemUI/compose/core/tests/src/com/android/compose/gesture/NestedDraggableTest.kt +36 −0 Original line number Diff line number Diff line Loading @@ -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 { Loading Loading @@ -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 Loading Loading @@ -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 Loading Loading
packages/SystemUI/compose/core/src/com/android/compose/gesture/NestedDraggable.kt +17 −2 Original line number Diff line number Diff line Loading @@ -111,6 +111,14 @@ interface NestedDraggable { fun shouldConsumeNestedPreScroll(sign: Float): Boolean = false 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. * Loading Loading @@ -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() } } Loading
packages/SystemUI/compose/core/tests/src/com/android/compose/gesture/NestedDraggableTest.kt +36 −0 Original line number Diff line number Diff line Loading @@ -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 { Loading Loading @@ -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 Loading Loading @@ -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 Loading