From ffb6a4c080a31685c8ad63de4443106e35336b0e Mon Sep 17 00:00:00 2001 From: Hasinjato Date: Tue, 23 Jun 2026 11:33:38 +0300 Subject: [PATCH] Add scrollbar desing for android on MyVerticalScrollbar --- .../mg/dot/feufaro/ui/MyVerticalScrollbar.kt | 111 +++++++++++++++++- 1 file changed, 107 insertions(+), 4 deletions(-) diff --git a/composeApp/src/androidMain/kotlin/mg/dot/feufaro/ui/MyVerticalScrollbar.kt b/composeApp/src/androidMain/kotlin/mg/dot/feufaro/ui/MyVerticalScrollbar.kt index cf52595..b2e2770 100644 --- a/composeApp/src/androidMain/kotlin/mg/dot/feufaro/ui/MyVerticalScrollbar.kt +++ b/composeApp/src/androidMain/kotlin/mg/dot/feufaro/ui/MyVerticalScrollbar.kt @@ -1,16 +1,119 @@ package mg.dot.feufaro.ui import androidx.compose.foundation.ScrollState +import androidx.compose.foundation.background +import androidx.compose.foundation.gestures.Orientation +import androidx.compose.foundation.gestures.draggable +import androidx.compose.foundation.gestures.rememberDraggableState +import androidx.compose.foundation.gestures.scrollBy +import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyListState -import androidx.compose.runtime.Composable +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.blur +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.layout.onGloballyPositioned +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.unit.dp +import kotlinx.coroutines.launch @Composable -actual fun MyVerticalScrollbar ( +actual fun MyVerticalScrollbar( modifier: Modifier, scrollState: ScrollState?, lazyListState: LazyListState?, content: @Composable () -> Unit -){ - content() +) { + val coroutineScope = rememberCoroutineScope() + val density = LocalDensity.current + + var containerHeight by remember { mutableStateOf(1f) } + val thumbHeight = 75.dp + + val scrollPercentage by remember(scrollState, lazyListState) { + derivedStateOf { + if (scrollState != null && scrollState.maxValue > 0) { + scrollState.value.toFloat() / scrollState.maxValue + } else if (lazyListState != null) { + val layoutInfo = lazyListState.layoutInfo + val totalItems = layoutInfo.totalItemsCount + if (totalItems == 0) 0f else { + val firstVisibleItem = lazyListState.firstVisibleItemIndex + firstVisibleItem.toFloat() / totalItems + } + } else { + 0f + } + } + } + + Box( + modifier = modifier.onGloballyPositioned { coordinates -> + containerHeight = coordinates.size.height.toFloat() + } + ) { + content() + + Box( + modifier = Modifier + .align(Alignment.CenterEnd) + .fillMaxHeight() + .width(15.dp) + .background(Color.Transparent) + ) { + val thumbHeightPx = with(density) { thumbHeight.toPx() } + val maxOffset = containerHeight - thumbHeightPx + val currentThumbOffset = (scrollPercentage * maxOffset).coerceIn(0f, maxOffset.coerceAtLeast(0f)) + + Box( + modifier = Modifier + .offset(y = with(density) { currentThumbOffset.toDp() }) + .width(10.dp) + .height(thumbHeight) + .align(Alignment.TopEnd) + .clip(RoundedCornerShape(5.dp)) + .background( + brush = Brush.verticalGradient( + colors = listOf( + MaterialTheme.colorScheme.secondary.copy(alpha = 1f), + MaterialTheme.colorScheme.secondary.copy(alpha = 0.75f), + MaterialTheme.colorScheme.secondary.copy(alpha = 0.5f) + ) + ) + ) + .draggable( + orientation = Orientation.Vertical, + state = rememberDraggableState { delta -> + coroutineScope.launch { + if (maxOffset > 0) { + val scrollRatio = delta / maxOffset + if (scrollState != null) { + scrollState.scrollBy(scrollRatio * scrollState.maxValue) + } else if (lazyListState != null) { + val totalItems = lazyListState.layoutInfo.totalItemsCount + lazyListState.scrollBy(scrollRatio * totalItems * 120f) + } + } + } + } + ) + ) { + Box( + modifier = Modifier + .align(Alignment.TopCenter) + .padding(top = 4.dp) + .size(6.dp) + .blur(1.dp) + .background(MaterialTheme.colorScheme.background, RoundedCornerShape(3.dp)) + ) + } + } + } } \ No newline at end of file