11
votes

Is there any way to add Scrollbars to add LazyColumn (ScrollableColumn is deprecated). The Javadoc doesn't mention anything about Scrollbars in Jetpack Compose.

Just to clarify, this is the design I want to implement: 1

Is it even possible to do that in Jetpack Compose yet? Or there are no support for Scrollbars?

2
No support for Scrollbars yet on Compose-Android, but it is now available for Compose-Desktop.Code Poet

2 Answers

10
votes

This is not yet possible in LazyColumn/LazyRow.

It is planned to be added at some point, but there is not yet a specific planned release for it. I'll update this answer when it is possible.

8
votes

It's actually possible now (they've added more stuff into LazyListState) and it's pretty easy to do. This is a pretty primitive scrollbar (always visible/can't drag/etc) and it uses item indexes to figure out thumb position so it may not look good when scrolling in lists with only few items:

  @Composable
  fun Modifier.simpleVerticalScrollbar(
    state: LazyListState,
    width: Dp = 8.dp
  ): Modifier {
    val targetAlpha = if (state.isScrollInProgress) 1f else 0f
    val duration = if (state.isScrollInProgress) 150 else 500

    val alpha by animateFloatAsState(
      targetValue = targetAlpha,
      animationSpec = tween(durationMillis = duration)
    )

    return drawWithContent {
      drawContent()

      val firstVisibleElementIndex = state.layoutInfo.visibleItemsInfo.firstOrNull()?.index
      val needDrawScrollbar = state.isScrollInProgress || alpha > 0.0f

      // Draw scrollbar if scrolling or if the animation is still running and lazy column has content
      if (needDrawScrollbar && firstVisibleElementIndex != null) {
        val elementHeight = this.size.height / state.layoutInfo.totalItemsCount
        val scrollbarOffsetY = firstVisibleElementIndex * elementHeight
        val scrollbarHeight = state.layoutInfo.visibleItemsInfo.size * elementHeight

        drawRect(
          color = Color.Red,
          topLeft = Offset(this.size.width - width.toPx(), scrollbarOffsetY),
          size = Size(width.toPx(), scrollbarHeight),
          alpha = alpha
        )
      }
    }
  }

UPD: I've updated the code. I've figured out how to show/hide scrollbar when LazyColumn is being scrolled or not + added fade in/out animation. I also changed drawBehind() to drawWithContent() because the former draws behind the content so it may probably draw on top of the scrollbar in some cases which is most likely not desireable.