Вопрос или проблема
Мой намерение – создать анимацию, в которой черный квадрат движется по горизонтали. Для этого, если я нажимаю на вторую кнопку, я увеличиваю смещение (координату 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")
}
}
}
}
Объяснение решения:
- Порядок применения модификаторов: Вы должны использовать модификатор
offset
доsize
. Это гарантирует, что коробка будет перемещаться, а не сжиматься. - Анимация: Анимация выполняется при нажатии на кнопки, которые изменяют значение
offsetX
и тем самым перемещают черный квадраты. - Структура: Мы также добавили
Spacer
между коробкой и кнопками для улучшения визуального восприятия.
Используя этот подход, вы достигнете желаемого эффекта движения черного квадрата, сохраняя его размеры на протяжении всей анимации.