Как сохранить размер при применении модификатора offset к Box?

Вопрос или проблема

Мой намерение – создать анимацию, в которой черный квадрат движется по горизонтали. Для этого, если я нажимаю на вторую кнопку, я увеличиваю смещение (координату x), а если нажимаю на первую кнопку, я возвращаюсь в начальное состояние.

@Composable
fun Screen() {
    val offsetX = remember { Animatable(0f) }
    val coroutineScope = rememberCoroutineScope()

    Column(
        Modifier
            .fillMaxSize()
            .padding(start = 16.dp, end = 16.dp, bottom = 16.dp),
        horizontalAlignment = Alignment.CenterHorizontally,
    ) {
        Box(
            modifier = Modifier
                .height(40.dp)
                .fillMaxWidth()
                .clip(CircleShape)
                .background(Color.White)
                .padding(horizontal = 4.dp, vertical = 2.dp),
        ) {
            Box(
                modifier = Modifier
                    .size(100.dp, 40.dp)
                    .clip(CircleShape)
                    .offset(x = offsetX.value.dp)
                    .background(Color.Black, CircleShape),
            )
        }

        Button(onClick = {
            coroutineScope.launch {
                offsetX.animateTo(0f, tween(400))
            }
        }) {
            Text("сбросить")
        }

        Button(onClick = {
            coroutineScope.launch {
                offsetX.animateTo(80f, tween(400))
            }
        }) {
            Text("80")
        }
    }
}

Я пытался создать анимацию перемещения квадрата, изменяя смещение (координату x). Однако, когда я увеличиваю смещение, начальная сторона движется, но конечная сторона – нет, поэтому эффект этого – уменьшение ширины, а не перемещение, что я и хочу сделать.

Начальная позиция черного квадрата по сравнению с после изменения смещения:


Модификатор offset должен предшествовать модификатору size:

modifier = Modifier
    .offset(x = offsetX.value.dp)
    .size(100.dp, 40.dp)
    .clip(CircleShape)
    .background(Color.Black, CircleShape)

Модификатор size определяет, где заканчивается содержимое. Когда вы применяете offset после, вы только изменяете, где начинается содержимое, конец останется там, где есть, и дополнительного измерения размера не происходит. Хотя это не явно прописано в последствиях, это также объясняется в документации:

Применение смещения меняет только положение содержимого, не вмешиваясь в его измерение размера.

@Composable
fun Screen() {

    val offsetX = remember { Animatable(0f) }
    val coroutineScope = rememberCoroutineScope()

    Column(
        Modifier
            .fillMaxSize()
            .padding(start = 16.dp, end = 16.dp, bottom = 16.dp),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Center // Центрировать содержимое по вертикали
    ) {
        Box(
            modifier = Modifier
                .height(40.dp)
                .fillMaxWidth()
                .clip(CircleShape)
                .background(Color.White)
                .padding(horizontal = 4.dp, vertical = 2.dp),
        ) {
            Box(
                modifier = Modifier
                    .size(100.dp, 40.dp)
                    .clip(CircleShape)
                    .offset(x = offsetX.value.dp) // Это будет перемещать квадрат по горизонтали
                    .background(Color.Black, CircleShape)
            )
        }

        Spacer(modifier = Modifier.height(16.dp)) // Добавить пространство между квадратом и кнопками

        Row(
            horizontalArrangement = Arrangement.spacedBy(16.dp) // Промежуток между кнопками
        ) {
            Button(onClick = {
                coroutineScope.launch {
                    offsetX.animateTo(0f, tween(400))
                }
            }) {
                Text("Сбросить")
            }

            Button(onClick = {
                coroutineScope.launch {
                    offsetX.animateTo(80f, tween(400))
                }
            }) {
                Text("80")
            }
        }
    }
}

Попробуйте это

Ответ или решение

Для того чтобы сохранить размеры коробки при применении модификатора offset в Jetpack Compose, необходимо убедиться, что порядок применения модификаторов является правильным. Как вы заметили в вашем коде, если вы применяете модификатор offset после модификатора size, то это приведет к изменению позиции коробки без учета её размера, что вызовет неправильное поведение при анимации.

Вот как правильно оформить код:

@Composable
fun Screen() {
    val offsetX = remember { Animatable(0f) }
    val coroutineScope = rememberCoroutineScope()

    Column(
        Modifier
            .fillMaxSize()
            .padding(start = 16.dp, end = 16.dp, bottom = 16.dp),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Center // Центрирование содержимого по вертикали
    ) {
        Box(
            modifier = Modifier
                .height(40.dp)
                .fillMaxWidth()
                .clip(CircleShape)
                .background(Color.White)
                .padding(horizontal = 4.dp, vertical = 2.dp),
        ) {
            Box(
                modifier = Modifier
                    .offset(x = offsetX.value.dp) // Сначала применяем offset
                    .size(100.dp, 40.dp) // Затем задаем размеры
                    .clip(CircleShape)
                    .background(Color.Black, CircleShape)
            )
        }

        Spacer(modifier = Modifier.height(16.dp)) // Добавляем пространство между коробкой и кнопками

        Row(
            horizontalArrangement = Arrangement.spacedBy(16.dp) // Промежуток между кнопками
        ) {
            Button(onClick = {
                coroutineScope.launch {
                    offsetX.animateTo(0f, tween(400)) // Возвращение в начальное положение
                }
            }) {
                Text("Сброс")
            }

            Button(onClick = {
                coroutineScope.launch {
                    offsetX.animateTo(80f, tween(400)) // Перемещение вправо на 80dp
                }
            }) {
                Text("80")
            }
        }
    }
}

Объяснение решения:

  1. Порядок применения модификаторов: Вы должны использовать модификатор offset до size. Это гарантирует, что коробка будет перемещаться, а не сжиматься.
  2. Анимация: Анимация выполняется при нажатии на кнопки, которые изменяют значение offsetX и тем самым перемещают черный квадраты.
  3. Структура: Мы также добавили Spacer между коробкой и кнопками для улучшения визуального восприятия.

Используя этот подход, вы достигнете желаемого эффекта движения черного квадрата, сохраняя его размеры на протяжении всей анимации.

Оцените материал
Добавить комментарий

Капча загружается...