Reorderable icon indicating copy to clipboard operation
Reorderable copied to clipboard

[Feature request] Add support for custom scroller

Open bkonrad-check opened this issue 11 months ago • 2 comments

We would like to overwrite the logic for the scroller within our implementation. We got a sticky header with a nested scrolling, which should scroll up, when we drag and element down. However, when the library calls scrollableState.animateScrollBy( diff, tween(durationMillis = duration.toInt(), easing = LinearEasing) ) the nested scrolling connection isn't working.

Due to this it would be nice, if the required Scroller could be an interface, which could be used for an custom implementation. This way we could pass the nested scroll connection or whatever we want to be scrolling to the rememberScroller and extend the logic you got.

Otherwise, maybe you have also an idea, why scrollableState.animateScrollBy doesn't work with the nested scrolling. lazyListState.animateScrollToItem(index) works fine.

Thanks in advance.

bkonrad-check avatar Jan 16 '25 10:01 bkonrad-check

I'll look into this tomorrow. Any chance you can a screen recording of a sample project that has the problem you're running into? Not sure if I understand exactly what's happening.

Calvin-LL avatar Jan 17 '25 08:01 Calvin-LL

https://github.com/user-attachments/assets/66b72107-8886-4a53-b3f4-cc7d1af20fd9

this is basically the issue I got. So manually scrolling works, but since I don't have control on the Scroller, I cannot scroll the top toolbar scrolling, when dragging.

Using this toolbar https://github.com/OyaCanli/tutorial_samples/blob/master/AppBarLayoutCompose/app/src/main/java/com/canlioya/appbarlayoutcompose/FlexibleTopBar.kt as sticky toolbar, integrated like this:

@OptIn(ExperimentalMaterial3Api::class)
@Composable
internal fun App() {
    PreComposeApp {
        ReorderableTheme {
            val navController = rememberNavigator()
            val showBackButton = navController.canGoBack.collectAsState(false)

            val topBarState = rememberTopAppBarState()
            val topAppBarScrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior(
                topBarState,
                snapAnimationSpec = null
            )

            CompositionLocalProvider(
                LocalMinimumInteractiveComponentSize provides Dp.Unspecified
            ) {
                Scaffold(
                    topBar = {
                        Column {
                            CenterAlignedTopAppBar(
                                title = { Text("Reorderable Demo") },
                                navigationIcon = { if (showBackButton.value) BackArrow(navController::popBackStack) },
                            )
                            FlexibleTopBar(
                                scrollBehavior = topAppBarScrollBehavior,
                                modifier = Modifier
                                    .fillMaxWidth()
                                    .background(Color.Blue)
                            ) {
                                Column(Modifier.height(150.dp)) {  }
                            }
                        }

                    },
                    content = {
                        Box(modifier = Modifier.padding(it)) {
                            NavHost(
                                navController,
                                modifier = Modifier.background(MaterialTheme.colorScheme.background)
                                    .nestedScroll(topAppBarScrollBehavior.nestedScrollConnection),
                                initialRoute = "main",
                            ) {
                                scene("main") { MainScreen(navController) }
                                scene("SimpleReorderableLazyColumn") { SimpleReorderableLazyColumnScreen() }
                                scene("ComplexReorderableLazyColumn") { ComplexReorderableLazyColumnScreen() }
                                scene("SimpleLongPressHandleReorderableLazyColumn") { SimpleLongPressHandleReorderableLazyColumnScreen() }
                                scene("SimpleReorderableLazyVerticalGrid") { SimpleReorderableLazyVerticalGridScreen() }
                                scene("SimpleReorderableLazyVerticalStaggeredGrid") { SimpleReorderableLazyVerticalStaggeredGridScreen() }
                                scene("ReorderableColumn") { ReorderableColumnScreen() }
                                scene("LongPressHandleReorderableColumn") { LongPressHandleReorderableColumnScreen() }
                                scene("SimpleReorderableLazyRow") { SimpleReorderableLazyRowScreen() }
                                scene("ComplexReorderableLazyRow") { ComplexReorderableLazyRowScreen() }
                                scene("SimpleReorderableLazyHorizontalGrid") { SimpleReorderableLazyHorizontalGridScreen() }
                                scene("SimpleReorderableLazyHorizontalStaggeredGrid") { SimpleReorderableLazyHorizontalStaggeredGridScreen() }
                                scene("ReorderableRow") { ReorderableRowScreen() }
                            }
                        }
                    }
                )
            }
        }
    }
}

Edit: To be clear, I want the possibility, that we can just use an own implementation for scroller, that way I could use the scroller to also scroll down the header by passing the topAppBarScrollBehavior.

bkonrad-check avatar Jan 17 '25 09:01 bkonrad-check

I can't think of a good way to do this :(

Calvin-LL avatar Jun 07 '25 04:06 Calvin-LL