Вопрос или проблема
Я хочу сделать анимированный круг в Jetpack Compose, чтобы он анимировался, как на картинке. Я не смог сделать это так, как хотел. Код представлен ниже.
круг
val transition = rememberInfiniteTransition()
val scale = transition.animateFloat(
initialValue = 1.9f,
targetValue = if(isAnimating) 2.05f else 1.9f,
animationSpec = infiniteRepeatable(
animation = tween(durationMillis = 1000, easing = FastOutSlowInEasing),
repeatMode = RepeatMode.Reverse
)
)
val deformFactor = transition.animateFloat(
initialValue = 0f,
targetValue = if(isAnimating) randomFloatInRange(0.1f, 0.2f) else 0f,
animationSpec = infiniteRepeatable(
animation = tween(durationMillis = 1000, easing = LinearOutSlowInEasing),
repeatMode = RepeatMode.Reverse
)
)
Canvas(modifier = Modifier
.fillMaxSize()) {
val center = Offset(size.width / 2, size.height / 2)
val radius = 100f * scale.value
val path = Path()
path.moveTo(center.x + radius * (1 - deformFactor.value), center.y)
for (angle in 0..360 step 10) {
val rad = Math.toRadians(angle.toDouble())
val x = center.x + radius * (1 + deformFactor.value * Math.sin(rad * 5)) * Math.cos(rad)
val y = center.y + radius * (1 + deformFactor.value * Math.sin(rad * 5)) * Math.sin(rad)
path.lineTo(x.toFloat(), y.toFloat())
}
path.close()
drawPath(path, color.value)
}
Ответ или решение
Для создания анимированного круга в Jetpack Compose, который будет выглядеть так, как показано на изображении, можно использовать подход, основанный на анимации с помощью rememberInfiniteTransition
и Canvas
. Я приведу пример кода, который должен помочь вам достичь желаемого эффекта.
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.*
import androidx.compose.ui.GeometricTransform
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Path
import androidx.compose.ui.graphics.drawscope.DrawScope
import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.delay
import kotlin.math.cos
import kotlin.math.sin
import kotlin.math.PI
import kotlin.random.Random
@Composable
fun AnimatedCircle(isAnimating: Boolean) {
val transition = rememberInfiniteTransition()
val scale = transition.animateFloat(
initialValue = 1.9f,
targetValue = if(isAnimating) 2.05f else 1.9f,
animationSpec = infiniteRepeatable(
animation = tween(durationMillis = 1000, easing = FastOutSlowInEasing),
repeatMode = RepeatMode.Reverse
)
)
val deformFactor = transition.animateFloat(
initialValue = 0f,
targetValue = if(isAnimating) Random.nextFloat() * (0.2f - 0.1f) + 0.1f else 0f,
animationSpec = infiniteRepeatable(
animation = tween(durationMillis = 1000, easing = LinearOutSlowInEasing),
repeatMode = RepeatMode.Reverse
)
)
Canvas(modifier = Modifier.fillMaxSize().background(MaterialTheme.colorScheme.background)) {
val center = center
val radius = 100f * scale.value
val path = Path()
path.moveTo(center.x + radius * (1 - deformFactor.value), center.y)
for (angle in 0..360 step 10) {
val rad = Math.toRadians(angle.toDouble())
val x = center.x + radius * (1 + deformFactor.value * sin(rad * 5)) * cos(rad)
val y = center.y + radius * (1 + deformFactor.value * sin(rad * 5)) * sin(rad)
path.lineTo(x.toFloat(), y.toFloat())
}
path.close()
drawPath(path, color = Color.Blue, style = Stroke(width = 4.dp.toPx()))
}
}
@Composable
fun MainScreen() {
var isAnimating by remember { mutableStateOf(true) }
AnimatedCircle(isAnimating = isAnimating)
// Для управления анимацией можно добавить логику, например, по клику
Modifier.pointerInput(Unit) {
detectTapGestures(onClick = {
isAnimating = !isAnimating
})
}
}
Объяснение кода:
-
Анимация: Мы используем
rememberInfiniteTransition
для создания двух анимаций: одна для изменения масштаба (вызывающая эффект увеличения и уменьшения размера), а другая – для деформации круга (создающая эффект волны на границе). -
Path: Мы строим
Path
, представляющий форму круга с использованием математических функций синуса и косинуса, изменяя радиус и добавляя деформацию в зависимости от текущего значения анимации. -
Canvas: Мы используем
Canvas
для рисования круга с анимацией. -
Обработка клика: Для управления запуском и остановкой анимации можно добавить обработчик кликов.
Этот код создаст анимированный круг, который будет плавно изменять форму и размер в зависимости от анимации. Вы можете изменить параметры анимации для достижения нужного эффекта.