androidandroid-jetpack-compose

Jetpack Compose Scrollbars


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 is no support for Scrollbars?


Solution

  • 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.