I made scrollable content, but how to add scrollbarThumbVertical
?
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.SpaceBetween,
horizontalAlignment = Alignment.CenterHorizontally
) {
Column(
modifier = Modifier
.fillMaxWidth()
.verticalScroll(rememberScrollState())//how to add here scrollbar?
.weight(1f, fill = false)
) {
//content
}
//another not scrollable content
}
To add a scrollbar along with verticalScroll or horizontalScroll modifier (Supports both LTR and RTL Layout directions). You can configure the scrollbar using scrollbarConfig parameter.
fun Modifier.scrollbar(
scrollState: ScrollState,
direction: Orientation,
config: ScrollbarConfig = ScrollbarConfig(),
): Modifier = composed {
var (
indicatorThickness, indicatorColor, indicatorCornerRadius,
alpha, alphaAnimationSpec, padding
) = config
val isScrollingOrPanning = scrollState.isScrollInProgress
val isVertical = direction == Orientation.Vertical
alpha = alpha ?: if (isScrollingOrPanning) 0.8f else 0f
alphaAnimationSpec = alphaAnimationSpec ?: tween(
delayMillis = if (isScrollingOrPanning) 0 else 1500,
durationMillis = if (isScrollingOrPanning) 150 else 500
)
val scrollbarAlpha by animateFloatAsState(alpha, alphaAnimationSpec)
drawWithContent {
drawContent()
val showScrollbar = isScrollingOrPanning || scrollbarAlpha > 0.0f
// Draw scrollbar only if currently scrolling or if scroll animation is ongoing.
if (showScrollbar) {
val (topPadding, bottomPadding, startPadding, endPadding) = arrayOf(
padding.calculateTopPadding().toPx(), padding.calculateBottomPadding().toPx(),
padding.calculateStartPadding(layoutDirection).toPx(),
padding.calculateEndPadding(layoutDirection).toPx()
)
val isLtr = layoutDirection == LayoutDirection.Ltr
val contentOffset = scrollState.value
val viewPortLength = if (isVertical) size.height else size.width
val viewPortCrossAxisLength = if (isVertical) size.width else size.height
val contentLength = max(viewPortLength + scrollState.maxValue, 0.001f /* To prevent divide by zero error */)
val scrollbarLength = viewPortLength -
(if (isVertical) topPadding + bottomPadding else startPadding + endPadding)
val indicatorThicknessPx = indicatorThickness.toPx()
val indicatorLength = max((scrollbarLength / contentLength) * viewPortLength, 20f.dp.toPx())
val indicatorOffset = (scrollbarLength / contentLength) * contentOffset
val scrollIndicatorSize = if (isVertical) Size(indicatorThicknessPx, indicatorLength)
else Size(indicatorLength, indicatorThicknessPx)
val scrollIndicatorPosition = if (isVertical)
Offset(
x = if (isLtr) viewPortCrossAxisLength - indicatorThicknessPx - endPadding
else startPadding,
y = indicatorOffset + topPadding
)
else
Offset(
x = if (isLtr) indicatorOffset + startPadding
else viewPortLength - indicatorOffset - indicatorLength - endPadding,
y = viewPortCrossAxisLength - indicatorThicknessPx - bottomPadding
)
drawRoundRect(
color = indicatorColor,
cornerRadius = indicatorCornerRadius.let { CornerRadius(it.toPx(), it.toPx()) },
topLeft = scrollIndicatorPosition,
size = scrollIndicatorSize,
alpha = scrollbarAlpha
)
}
}
}
data class ScrollbarConfig(
val indicatorThickness: Dp = 8.dp,
val indicatorColor: Color = Color.Gray.copy(alpha = 0.7f),
val indicatorCornerRadius: Dp = indicatorThickness / 2,
val alpha: Float? = null,
val alphaAnimationSpec: AnimationSpec<Float>? = null,
val padding: PaddingValues = PaddingValues(all = 0.dp),
)
fun Modifier.verticalScrollWithScrollbar(
scrollState: ScrollState,
enabled: Boolean = true,
flingBehavior: FlingBehavior? = null,
reverseScrolling: Boolean = false,
scrollbarConfig: ScrollbarConfig = ScrollbarConfig()
): Modifier = this
.scrollbar(scrollState, direction = Orientation.Vertical, config = scrollbarConfig)
.verticalScroll(scrollState, enabled, flingBehavior, reverseScrolling)
fun Modifier.horizontalScrollWithScrollbar(
scrollState: ScrollState,
enabled: Boolean = true,
flingBehavior: FlingBehavior? = null,
reverseScrolling: Boolean = false,
scrollbarConfig: ScrollbarConfig = ScrollbarConfig()
): Modifier = this
.scrollbar(scrollState, direction = Orientation.Horizontal, config = scrollbarConfig)
.horizontalScroll(scrollState, enabled, flingBehavior, reverseScrolling)
Usage example:
Column(
Modifier
.fillMaxWidth()
.heightIn(max = 300.dp)
.padding(4.dp)
.border(1.dp, Color.Gray, RoundedCornerShape(8.dp))
.verticalScrollWithScrollbar(
rememberScrollState(),
scrollbarConfig = ScrollbarConfig(
padding = PaddingValues(4.dp, 4.dp, 4.dp, 4.dp)
)
)
) {
Text(
text = "Some very long scrollable text",
color = Color.Gray,
modifier = Modifier.padding(vertical = 4.dp)
)
}