Değere dayalı animasyonlar

animate*AsState ile tek bir değeri canlandırın

animate*AsState işlevleri, Compose'daki en basit animasyon API'leridir. tek bir değer canlandırıyor. Yalnızca hedef değeri (veya bitiş değerini) sağlamanız ve API, animasyonu geçerli değerden belirtilen değere başlatır.

Aşağıda, bu API'yi kullanarak alfa testi uygulama örneği verilmiştir. Yalnızca animateFloatAsState için hedef değere ayarlanmışsa alfa değeri artık bir animasyon değeridir sağlanan değerler arasına (bu örnekte 1f veya 0.5f) girin.

var enabled by remember { mutableStateOf(true) }

val alpha: Float by animateFloatAsState(if (enabled) 1f else 0.5f)
Box(
    Modifier.fillMaxSize()
        .graphicsLayer(alpha = alpha)
        .background(Color.Red)
)

Herhangi bir animasyon sınıfının veya işleyicinin örneğini oluşturmanız gerekmediğini unutmayın. neden olabilir. Gelişmiş seçenekte, bir animasyon nesnesi (yani Animatable örneği) çağrı sitesinde oluşturulur ve hatırlanır. olduğunu varsayalım. Bundan sonra, bu composable'ı sağladığınızda bir animasyon otomatik olarak başlatılır ve bu, değer. Yayında zaten bir animasyon varsa animasyon kendi geçerli değer (ve hız) gösterilir ve animasyon hedef değere doğru ilerler. Etkinlik sırasında bu composable yeniden derlenir ve güncellenmiş bir animasyon döndürür ne kadar değer verdiğinizi gösterir.

Compose, Float için animate*AsState işlevleri sunar. Color, Dp, Size, Offset, Rect, Int, IntOffset ve IntSize Bir TwoWayConverter - animateValueAsState, genel bir tür alır.

Bir AnimationSpec sağlayarak animasyon özelliklerini özelleştirebilirsiniz. Daha fazla bilgi için AnimationSpec öğesine bakın.

Bir geçişle birden fazla mülkü aynı anda canlandırma

Transition, bir veya daha fazla animasyonu alt öğeleri olarak yönetir ve çalıştırır aynı anda birkaç farklı durumda.

Eyaletler herhangi bir veri türünde olabilir. Çoğu durumda özel bir enum kullanabilirsiniz. türünü ekleyin:

enum class BoxState {
    Collapsed,
    Expanded
}

updateTransition, Transition örneği ile güncellemeleri oluşturup hatırlar durumu.

var currentState by remember { mutableStateOf(BoxState.Collapsed) }
val transition = updateTransition(currentState, label = "box state")

Ardından, bir alt öğe tanımlamak için animate* uzantı işlevinden birini kullanabilirsiniz animasyonu gösterilir. Eyaletlerin her biri için hedef değerleri belirtin. Bu animate* işlevleri, her karede güncellenen bir animasyon değeri döndürür. güncellendiğinde animasyon sırasında updateTransition.

val rect by transition.animateRect(label = "rectangle") { state ->
    when (state) {
        BoxState.Collapsed -> Rect(0f, 0f, 100f, 100f)
        BoxState.Expanded -> Rect(100f, 100f, 300f, 300f)
    }
}
val borderWidth by transition.animateDp(label = "border width") { state ->
    when (state) {
        BoxState.Collapsed -> 1.dp
        BoxState.Expanded -> 0.dp
    }
}

İsteğe bağlı olarak, farklı bir transitionSpec parametresi belirtmek için Geçiş durumu değişikliklerinin her bir kombinasyonu için AnimationSpec. Görüntüleyin AnimasyonSpec bölümüne göz atın.

val color by transition.animateColor(
    transitionSpec = {
        when {
            BoxState.Expanded isTransitioningTo BoxState.Collapsed ->
                spring(stiffness = 50f)
            else ->
                tween(durationMillis = 500)
        }
    }, label = "color"
) { state ->
    when (state) {
        BoxState.Collapsed -> MaterialTheme.colorScheme.primary
        BoxState.Expanded -> MaterialTheme.colorScheme.background
    }
}

Bir geçiş hedef duruma ulaştığında, Transition.currentState Transition.targetState ile aynı olur. Bu, dönüşüm işlemi için tamamlanıp tamamlanmadığını görebilirsiniz.

Bazen ilk hedeften farklı bir başlangıç durumu olmasını isteriz. durumu. Şunları elde etmek için MutableTransitionState ile updateTransition kullanabiliriz: bu. Örneğin, kod girer girmez animasyonu başlatmamıza olanak bileşimi.

// Start in collapsed state and immediately animate to expanded
var currentState = remember { MutableTransitionState(BoxState.Collapsed) }
currentState.targetState = BoxState.Expanded
val transition = updateTransition(currentState, label = "box state")
// ……

Birden fazla composable işlev içeren daha karmaşık bir geçiş için createChildTransition kullanılır alt geçiş oluşturun. Bu teknik, endişeleri ayırmak için yararlıdır. birden fazla alt bileşene odaklanmasını sağlar. Üst geçiş işlemi, alt geçişlerdeki tüm animasyon değerlerine dikkat edin.

enum class DialerState { DialerMinimized, NumberPad }

@Composable
fun DialerButton(isVisibleTransition: Transition<Boolean>) {
    // `isVisibleTransition` spares the need for the content to know
    // about other DialerStates. Instead, the content can focus on
    // animating the state change between visible and not visible.
}

@Composable
fun NumberPad(isVisibleTransition: Transition<Boolean>) {
    // `isVisibleTransition` spares the need for the content to know
    // about other DialerStates. Instead, the content can focus on
    // animating the state change between visible and not visible.
}

@Composable
fun Dialer(dialerState: DialerState) {
    val transition = updateTransition(dialerState, label = "dialer state")
    Box {
        // Creates separate child transitions of Boolean type for NumberPad
        // and DialerButton for any content animation between visible and
        // not visible
        NumberPad(
            transition.createChildTransition {
                it == DialerState.NumberPad
            }
        )
        DialerButton(
            transition.createChildTransition {
                it == DialerState.DialerMinimized
            }
        )
    }
}

AnimatedVisibility ve AnimatedContent ile geçişi kullanın

AnimatedVisibility ve AnimatedContent Transition öğesinin uzantı işlevleri olarak kullanılabilir. Şu tarih için targetState: Transition.AnimatedVisibility ve Transition.AnimatedContent türetildi ve giriş/çıkış geçişlerini gerektiği gibi tetiklemek içinTransition Transition adlı çocuğun targetState ayarı değişti. Bu uzantı işlevleri için dahili olacak olan Enter/exit/sizeTransform animasyonları AnimatedVisibility/AnimatedContent, Transition içine kaldırılacak. Bu uzantı işlevleriyle, AnimatedVisibility/AnimatedContent öğesinin durumu gözlemlenebilirsiniz. Boole visible parametresi yerine, AnimatedVisibility uygulamasının bu sürümü, üst öğeyi dönüştüren bir lambda alıyor geçişin hedef durumunu boole'ye dönüştürür.

Ayrıntılar için Animated visibility ve AnimatedContent'e göz atın.

var selected by remember { mutableStateOf(false) }
// Animates changes when `selected` is changed.
val transition = updateTransition(selected, label = "selected state")
val borderColor by transition.animateColor(label = "border color") { isSelected ->
    if (isSelected) Color.Magenta else Color.White
}
val elevation by transition.animateDp(label = "elevation") { isSelected ->
    if (isSelected) 10.dp else 2.dp
}
Surface(
    onClick = { selected = !selected },
    shape = RoundedCornerShape(8.dp),
    border = BorderStroke(2.dp, borderColor),
    elevation = elevation
) {
    Column(modifier = Modifier.fillMaxWidth().padding(16.dp)) {
        Text(text = "Hello, world!")
        // AnimatedVisibility as a part of the transition.
        transition.AnimatedVisibility(
            visible = { targetSelected -> targetSelected },
            enter = expandVertically(),
            exit = shrinkVertically()
        ) {
            Text(text = "It is fine today.")
        }
        // AnimatedContent as a part of the transition.
        transition.AnimatedContent { targetState ->
            if (targetState) {
                Text(text = "Selected")
            } else {
                Icon(imageVector = Icons.Default.Phone, contentDescription = "Phone")
            }
        }
    }
}

Bir geçişi kapsama ve yeniden kullanılabilir hale getirme

Basit kullanım alanları için, geçiş animasyonlarını son derece geçerli bir seçenek. Karmaşık bir bileşen üzerinde çalışırken ancak animasyonlu değerleri birbirinden ayırmak isteyebilirsiniz. composable kullanıcı arayüzünden uygulanmasını sağlar.

Bunu, tüm animasyon değerlerini içeren bir sınıf ve söz konusu sınıfın bir örneğini döndüren "update" işlevi. Geçiş çıkarımı da yeni ayrı işleve çıkarılabilir. Bu kalıp animasyon mantığını merkezileştirme veya karmaşık hale getirme konusunda kullanışlıdır. animasyonları yeniden kullanabilirsiniz.

enum class BoxState { Collapsed, Expanded }

@Composable
fun AnimatingBox(boxState: BoxState) {
    val transitionData = updateTransitionData(boxState)
    // UI tree
    Box(
        modifier = Modifier
            .background(transitionData.color)
            .size(transitionData.size)
    )
}

// Holds the animation values.
private class TransitionData(
    color: State<Color>,
    size: State<Dp>
) {
    val color by color
    val size by size
}

// Create a Transition and return its animation values.
@Composable
private fun updateTransitionData(boxState: BoxState): TransitionData {
    val transition = updateTransition(boxState, label = "box state")
    val color = transition.animateColor(label = "color") { state ->
        when (state) {
            BoxState.Collapsed -> Color.Gray
            BoxState.Expanded -> Color.Red
        }
    }
    val size = transition.animateDp(label = "size") { state ->
        when (state) {
            BoxState.Collapsed -> 64.dp
            BoxState.Expanded -> 128.dp
        }
    }
    return remember(transition) { TransitionData(color, size) }
}

rememberInfiniteTransition ile sonsuz sayıda tekrar eden bir animasyon oluşturun

InfiniteTransition, Transition gibi bir veya daha fazla alt animasyon içerir, ancak besteye girdikleri anda animasyonlar çalışmaya başlar ve devam eder. InfiniteTransition örneği oluşturabilirsiniz rememberInfiniteTransition ile. Alt animasyonlar animateColor, animatedFloat veya animatedValue. Ayrıca, Animasyonu belirtmek için infinite Repeatable özellikler.

val infiniteTransition = rememberInfiniteTransition()
val color by infiniteTransition.animateColor(
    initialValue = Color.Red,
    targetValue = Color.Green,
    animationSpec = infiniteRepeatable(
        animation = tween(1000, easing = LinearEasing),
        repeatMode = RepeatMode.Reverse
    )
)

Box(Modifier.fillMaxSize().background(color))

Alt düzey animasyon API'leri

Önceki bölümde bahsedilen tüm üst düzey animasyon API'leri en iyi uygulamaları paylaşacağım.

animate*AsState işlevleri, anında görsel oluşturan en basit API'lerdir değerinin animasyon değeri olarak değişmesi. Desteklenen bir kaynak olan Animatable, eş yordam tabanlı API'dir. updateTransition, birden fazla animasyon değerini yönetebilen ve bunları temel alarak çalıştırabilen geçiş nesnesi tercih edebilirsiniz. rememberInfiniteTransition benzer ancak çalışmaya devam eden birden çok animasyonu yönetebilen sonsuz geçiş koruyabilmelidir. Animatable hariç tüm bu API'ler composable'dır. bu animasyonların bestenin dışında oluşturulabileceği anlamına gelir.

Bu API'lerin tümü daha temel Animation API'ye dayanır. En fazla Uygulamalar doğrudan Animation ile etkileşime geçmeyecek. Özelleştirmenin bir kısmı Animation özellikleri üst düzey API'ler aracılığıyla kullanılabilir. Görüntüleyin Aşağıdakiler hakkında daha fazla bilgi için animasyonları özelleştirme AnimationVector ve AnimationSpec.

Çeşitli alt düzey animasyon API&#39;leri arasındaki ilişkiyi gösteren şema

Animatable: Koordine tabanlı tek değerli animasyon

Animatable, değeri değiştirildiğinde değeri animasyon oluşturabilen bir değer sahibidir. animateTo. Bu, animate*AsState uygulamasını yedekleyen API'dir. Tutarlı bir devamlılık ve karşılıklı dışlama sağlar. Diğer bir deyişle, değer değişikliği her zaman devam eder ve devam eden animasyonlar iptal edilir.

Animatable ürününün animateTo dahil birçok özelliği askıya alma olarak sunuluyor işlevlerine dahildir. Bu, öğelerin uygun bir eş yordam içine alınması gerektiği anlamına gelir kapsam. Örneğin, LaunchedEffect composable'ı kullanarak kapsamı yalnızca belirtilen anahtar değeri süresince uygular.

// Start out gray and animate to green/red based on `ok`
val color = remember { Animatable(Color.Gray) }
LaunchedEffect(ok) {
    color.animateTo(if (ok) Color.Green else Color.Red)
}
Box(Modifier.fillMaxSize().background(color.value))

Yukarıdaki örnekte, Animatable örneği oluşturup hatırlayacağız. Color.Gray başlangıç değeri. Boole işaretinin değerine bağlı olarak ok, renk canlandırmasını Color.Green veya Color.Red olarak gösterir. Sonraki herhangi bir boole değerine geçiş yapıldığında animasyon diğer renge başlar. Bir animasyon iptal edildiğinde ve yeni animasyon, geçerli hızla geçerli anlık görüntü değerinden başlar.

Bu, animate*AsState API'yi yedekleyen animasyon uygulamasıdır ele alacağız. animate*AsState ile karşılaştırıldığında, Animatable doğrudan bize çeşitli konularda daha ayrıntılı kontrol sağlar. İlk olarak, Animatable, ilk hedef değerinden farklı bir başlangıç değerine sahip olabilir. Örneğin, yukarıdaki kod örneğinde ilk başta gri bir kutu gösterilmektedir. yeşile veya kırmızıya dönüşmeye başlar. İkinci olarak, Animatable snapTo ve animateDecay olmak üzere içerik değerine ilişkin işlemlerdir. snapTo. geçerli değeri hemen hedef değere ayarlar. Bu, tek doğru kaynağı değildir ve diğer reklam biçimleriyle (ör. dokunma etkinlikleri) animateDecay, yavaşlayan bir animasyon başlatır kaldırmamız gerekir. Bu, hızla kaydırma davranışını uygulamak için yararlıdır. Görüntüleyin Daha fazla bilgi için hareket ve animasyon.

Animatable, Float ve Color özelliklerini hemen destekler ancak tüm veri türleri aşağıdaki gibi olabilir: bir TwoWayConverter sağlanarak kullanılabilir. Görüntüleyin AnimasyonVector sayfasına göz atın.

AnimationSpec sağlayarak animasyon özelliklerini özelleştirebilirsiniz. Daha fazla bilgi için AnimationSpec öğesine bakın.

Animation: Manuel olarak kontrol edilen animasyon

Animation, kullanılabilen en düşük düzey Animasyon API'sidir. Animasyonların çoğu temel aldığı bir etkinlik geliştirdik. İki Animation alt türü vardır: TargetBasedAnimation ve DecayAnimation.

Animation, yalnızca animasyonun zamanını manuel olarak kontrol etmek için kullanılmalıdır. Animation, durum bilgisizdir ve herhangi bir yaşam döngüsü kavramı yoktur. Google üst düzey API'lerin kullandığı bir animasyon hesaplama motoru görevi görür.

TargetBasedAnimation

Diğer API'ler çoğu kullanım alanını kapsar ancak doğrudan TargetBasedAnimation kullanılır animasyon oynatma süresini kendiniz kontrol etmenizi sağlar. Aşağıdaki örnekte, TargetAnimation cihazının oynatma süresi, kareye göre manuel olarak kontrol edilir. saat withFrameNanos tarafından sağlanmıştır.

val anim = remember {
    TargetBasedAnimation(
        animationSpec = tween(200),
        typeConverter = Float.VectorConverter,
        initialValue = 200f,
        targetValue = 1000f
    )
}
var playTime by remember { mutableStateOf(0L) }

LaunchedEffect(anim) {
    val startTime = withFrameNanos { it }

    do {
        playTime = withFrameNanos { it } - startTime
        val animationValue = anim.getValueFromNanos(playTime)
    } while (someCustomCondition())
}

DecayAnimation

TargetBasedAnimation özelliğinden farklı olarak, DecayAnimation bir targetValue sağlanmasını gerektirmez. Bunun yerine, Başlangıç koşullarına göre targetValue, initialVelocity ve initialValue ve sağlanan DecayAnimationSpec.

Azaltma animasyonları, genellikle bir sallama hareketinden sonra öğeleri yavaşlatmak için kullanılır. dur. Animasyon hızı, initialVelocityVector tarafından ayarlanan değerde başlar zamanla yavaşlar.

ziyaret edin.