oleksandrbalan / minabox

Lazy box library for Jetpack Compose, which allows to display lazy loaded items on the 2D plane.
Apache License 2.0
302 stars 18 forks source link

ScrollbarAdapter #12

Closed snakemr closed 9 months ago

snakemr commented 1 year ago

Hi, Is there any ScrollbarAdapter for MinaBox / LazyTable states?

oleksandrbalan commented 1 year ago

Hi 👋

I am not sure what do you mean by "adapters", but you could fairly easy draw some scrollbars on canvas using translate state property of the MinaBoxState.

For example it could be something like this:

@Composable
private fun Scrollbars(
    translate: MinaBoxState.Translate,
    modifier: Modifier = Modifier
) {
    val scrollbarsWidth = 4.dp
    val scrollbarsColor = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.5f)
    Canvas(modifier) {
        val scrollbarsWidthPx = scrollbarsWidth.roundToPx()

        val totalHeight = translate.maxY + size.height
        val verticalRatio = totalHeight / size.height
        val startY = translate.y / verticalRatio
        val endY = (translate.y + size.height) / verticalRatio

        drawLine(
            color = scrollbarsColor,
            start = Offset(size.width - scrollbarsWidthPx / 2, startY),
            end = Offset(size.width - scrollbarsWidthPx / 2, endY),
            strokeWidth = scrollbarsWidthPx.toFloat(),
            cap = StrokeCap.Round,
        )

        val totalWidth = translate.maxX + size.width
        val horizontalRatio = totalWidth / size.width
        val startX = translate.x / horizontalRatio
        val endX = (translate.x + size.width) / horizontalRatio

        drawLine(
            color = scrollbarsColor,
            start = Offset(startX, size.height - scrollbarsWidthPx / 2),
            end = Offset(endX, size.height - scrollbarsWidthPx / 2),
            strokeWidth = scrollbarsWidthPx.toFloat(),
            cap = StrokeCap.Round,
        )
    }
}

With a usage inside a Box over the MinaBox layout:

Box {
    val state = rememberMinaBoxState()

    MinaBox(
        state = state,
        modifier = Modifier.fillMaxSize()
    ) { ... }

    val translate = state.translate
    if (translate != null) {
        Scrollbars(
            translate = translate,
            modifier = Modifier.fillMaxSize()
        )
    }
}

https://github.com/oleksandrbalan/minabox/assets/20944869/cff57734-f959-40d1-990f-f0c37c40f682

In the LazyTable you could do the same, as you could reach for Translate through minaBoxState property.

val state = rememberLazyTableState()
val translate = state.minaBoxState.translate

If you want some interactive scrollbars (for desktop) I guess it could be achieved with the same math, but applied to the .offset() and .size() modifiers of some draggable composable elements.