Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 911
Yannick Avatar asked Feb 23 '21 22:02

Yannick


People also ask

How do you make a scrollable column in jetpack compose?

We can make the Column scrollable by using the verticalScroll() modifier.

What is LazyColumn in jetpack compose?

A LazyColumn is a vertically scrolling list that only composes and lays out the currently visible items. It's similar to a Recyclerview in the classic Android View system.

Is jetpack compose reactive?

Jetpack Compose is a modern toolkit designed to simplify UI development. It combines a reactive programming model with the conciseness and ease of use of the Kotlin programming language.

How do I turn off scrolling in lazy column?

PreventUserInput to prevent scrolling, and then use a do-nothing scroll at the same priority to cancel the first "scroll" and re-enable scrolling.


1 Answers

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.

like image 63
Dmitry Avatar answered Sep 18 '22 20:09

Dmitry