-1

In my Jetpack Compose project, one of my components uses a FlowRow from Accompanist. But I don't know how to make the FlowRow scroll to a given "node".

Here the relevant code from my @Composable:

sealed class MovesNavigatorElement(open val text: String)
data class MoveNumber(override val text: String) : MovesNavigatorElement(text)
data class HalfMoveSAN(override val text: String) : MovesNavigatorElement(text)

@Composable
fun MovesNavigator(modifier: Modifier = Modifier, elements: Array<MovesNavigatorElement>, mustBeVisibleByDefaultElementIndex: Int) {
    val vertScrollState = rememberScrollState()

    FlowRow(
        modifier = modifier
            .background(color = Color.Yellow.copy(alpha = 0.3f))
            .verticalScroll(vertScrollState),
        mainAxisSpacing = 10.dp,
        crossAxisSpacing = 15.dp,
    ) {
        elements.map {
            Text(text = it.text, fontSize = 34.sp, color = Color.Blue, style= MaterialTheme.typography.body1)
        }
    }
}

Where you can see that I declare the "nodes" of the FlowRow as a list : the parameter elements. Also I'm using a ScrollState in the local variable vertScrollState.

But, let's say that I want to make it scroll to elements[30] : how should I do that ? Given that mustBeVisibleByDefaultElementIndex is the index of the element that must be visible by default. I mean, when composition occurs. But the user can change the position later of course.

In other words :

  1. At composition : the element whose index is given is made visible
  2. Then, before any other composition occurs of course, the user can scroll it with the scrollbar.
loloof64
  • 5,252
  • 12
  • 41
  • 78

2 Answers2

1

You just need to use the method parameter,

val state = rememberScrollState(initial = mustBeVisibleByDefault)

Better press Ctrl + P to see all possible combinations before going to even the web.

I kept this in case if anyone finds it helpful bizarrely:-

The ScrollState exposes scrollTo and animateScrollTo methods. You can easily use them to achieve the desired result. Refer to the docs

Richard Onslow Roper
  • 5,477
  • 2
  • 11
  • 42
0

Here how I manage to solve (partially) my issue :

  1. use a plain ScrollState instead of rememberScrollState() : because even if I set scroll to a fixed value at recomposition, the user still will be able to move it. So, no need to "cache" the scroll value
  2. use sp to px conversion for the scroll amount which is expected a value in pixels, and an hard-coded division amount of the given index (that's why it is only partially solved)

Which led me to the following :

sealed class MovesNavigatorElement(open val text: String)
data class MoveNumber(override val text: String) : MovesNavigatorElement(text)
data class HalfMoveSAN(override val text: String) : MovesNavigatorElement(text)

@Composable
fun MovesNavigator(modifier: Modifier = Modifier, elements: Array<MovesNavigatorElement>, mustBeVisibleByDefaultElementIndex: Int = 0) {
    val lineHeightPixels = with(LocalDensity.current) {34.sp.toPx()}
    val scrollAmount = ((mustBeVisibleByDefaultElementIndex / 6) * lineHeightPixels).toInt()
    val vertScrollState = ScrollState(scrollAmount)

    FlowRow(
        modifier = modifier
            .background(color = Color.Yellow.copy(alpha = 0.3f))
            .verticalScroll(vertScrollState),
        mainAxisSpacing = 8.dp,
    ) {
        elements.map {
            Text(text = it.text, fontSize = 34.sp, color = Color.Blue, style= MaterialTheme.typography.body1)
        }
    }
}

But still have to test on several devices.

loloof64
  • 5,252
  • 12
  • 41
  • 78