2

Is there a way to horizontally scroll only to start or specified position of previous or next element with Jetpack Compose?

Snappy scrolling in RecyclerView

2
  • 1
    this is not yet supported, you can follow this issue for updates Commented Aug 22, 2021 at 17:14
  • 1
    Well, yes there is. Commented Aug 22, 2021 at 18:58

2 Answers 2

3

You can check the scrolling direction like so

@Composable private fun LazyListState.isScrollingUp(): Boolean { var previousIndex by remember(this) { mutableStateOf(firstVisibleItemIndex) } var previousScrollOffset by remember(this) { mutableStateOf(firstVisibleItemScrollOffset) } return remember(this) { derivedStateOf { if (previousIndex != firstVisibleItemIndex) { previousIndex > firstVisibleItemIndex } else { previousScrollOffset >= firstVisibleItemScrollOffset }.also { previousIndex = firstVisibleItemIndex previousScrollOffset = firstVisibleItemScrollOffset } } }.value } 

Of course, you will need to create a rememberLazyListState(), and then pass it to the list as a parameter.

Then, based upon the scrolling direction, you can call lazyListState.scrollTo(lazyListState.firstVisibleItemIndex + 1) in a coroutine (if the user is scrolling right), and appropriate calls for the other direction.

Sign up to request clarification or add additional context in comments.

2 Comments

can you provide more detailed example please how to use your code to achieve snapping behavior for lazryRow ?
Hello Hospes, appologies for the late reply. I am afraid I do not know of the exact implementation of the same. I know it can be done, but exactly how, I guess you would need to reference to docs and do some serious study to grab that. Apparently the OP already knew that, so upon my pointing in the direction, he could implement it on his own.
3

(Example for a horizontal LazyRow)

You could do a scroll to the next or previous item to create a snap effect. Check the offset of the first visible item to see which item of the list takes up more screen space and then scroll left or right to the most visible one.

@Composable fun SnappyLazyRow() { val listState = rememberLazyListState() val coroutineScope = rememberCoroutineScope() LazyRow( state = listState, modifier = Modifier.fillMaxSize(), content = { items(/*list of items*/) { index -> /* Item view */ if(!listState.isScrollInProgress){ if(listState.isHalfPastItemLeft()) coroutineScope.scrollBasic(listState, left = true) else coroutineScope.scrollBasic(listState) if(listState.isHalfPastItemRight()) coroutineScope.scrollBasic(listState) else coroutineScope.scrollBasic(listState, left = true) } } }) } private fun CoroutineScope.scrollBasic(listState: LazyListState, left: Boolean = false){ launch { val pos = if(left) listState.firstVisibleItemIndex else listState.firstVisibleItemIndex+1 listState.animateScrollToItem(pos) } } @Composable private fun LazyListState.isHalfPastItemRight(): Boolean { return firstVisibleItemScrollOffset > 500 } @Composable private fun LazyListState.isHalfPastItemLeft(): Boolean { return firstVisibleItemScrollOffset <= 500 } 

1 Comment

What is the 500 for?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.