Прокручиваемый TimeText в Jetpack Compose

Я делаю приложение для Wear OS с помощью Jetpack Compose. Я хочу, чтобы пользовательский интерфейс выглядел примерно так:

Это код, который у меня есть сейчас:

@Composable
fun DefaultPreview() {
    TimeText()
    ScalingLazyColumn(
        Modifier.fillMaxWidth(),
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        item {
            Text(
                text = "Title",
                style = MaterialTheme.typography.title1,
                color = MaterialTheme.colors.primary
            )
        }
        item {
            Text(
                text = "Caption",
                style = MaterialTheme.typography.caption1,
                color = MaterialTheme.colors.primary
            )
        }
        item {
            Column(horizontalAlignment = Alignment.CenterHorizontally) {
                Text(text = "Text content")
                repeat(10) { Text("Line $it") }
            }
        }
    }
}

Проблема в том, что когда я прокручиваю список, текст оказывается под TimeText, что на самом деле выглядит не очень хорошо.

Итак, я хочу сделать прокрутку TimeText вместе с другими текстовыми элементами. Если я помещу TimeText() как элемент в ScalingLazyColumn, то это сработает, но теперь под TimeText появится огромный пустой пробел, который, очевидно, является CurvedLayout.

Как мне избавиться от этого пустого места? Есть ли лучший способ сделать TimeText прокручиваемым?

оберните макет внутри столбца или добавьте верхнее дополнение в ScalingLazyColumn

shahid17june 30.04.2024 10:16

Если обернуть их в столбец, ScalingLazyColumn теперь полностью находится под CurvedLayout, сгенерированным TimeText, поэтому теперь он вообще не виден. Кроме того, я больше не могу даже прокрутить до ленивого столбца.

Anchith Acharya 04.05.2024 14:44
0
2
78
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Пустой пробел создается из-за CurvedLayout, созданного TimeText, размеры которого равны размеру всего экрана. Вне списка это не было бы проблемой, поскольку тогда наш контент просто накладывался бы поверх CurvedLayout. Но когда мы используем TimeText в списке, остальные элементы списка появляются под TimeText, а не над ним.

Я не мог придумать, как заставить TimeText вести себя как элемент списка, одновременно располагая другие элементы списка сверху. Я также не смог придумать, как отрезать пустую часть TimeText (Modifier.clip меняет только то, что нарисовано, но не меняет размеры составного объекта.

Поэтому я попробовал другой подход, задав вертикальное смещение TimeText, которое синхронизировалось бы с прокруткой ScalingLazyColumn. К сожалению, не существует прямого способа получить абсолютное значение прокрутки из ScalingLazyListState, поэтому мне пришлось прибегнуть к хакерскому методу, используя Modifier.onGloballyPositioned в первом элементе ScalingLazyColumn.

@Composable
fun DefaultPreview() {
    val scalingLazyListState = rememberScalingLazyListState()

    var initialTimeTextOffset by remember { mutableFloatStateOf(0f) }
    var timeTextOffset by remember { mutableFloatStateOf(0f) }

    TimeText(Modifier.offset(y=timeTextOffset.dp))
    ScalingLazyColumn(
        Modifier.fillMaxWidth(),
        horizontalAlignment = Alignment.CenterHorizontally,
        state = scalingLazyListState
    ) {
        item {
            Text(
                text = "Title",
                style = MaterialTheme.typography.title1,
                color = MaterialTheme.colors.primary,
                modifier = Modifier.onGloballyPositioned {
                    if (scalingLazyListState.centerItemIndex == 1 && scalingLazyListState.centerItemScrollOffset == 0)
                        initialTimeTextOffset = it.positionInRoot().y
                    
                    // for some reason dividing the whole thing by 2 seems to make the animation more 'natural'
                    timeTextOffset = (it.positionInRoot().y - initialTimeTextOffset)/2
                }
            )
        }
        item {
            Text(
                text = "Caption",
                style = MaterialTheme.typography.caption1,
                color = MaterialTheme.colors.primary
            )
        }
        item {
            Column(horizontalAlignment = Alignment.CenterHorizontally) {
                Text(text = "Text content")
                repeat(10) { Text("Line $it") }
            }
        }
    }
}

Этот подход работает для меня, поэтому я пока отмечу вопрос как отвеченный. Но я не верю, что это «правильный» способ сделать это, и этот подход также может быть плохим с точки зрения производительности. Поэтому, если кто-то ответит с лучшим подходом, я отмечу это как ответ.

Другие вопросы по теме