वैल्यू के हिसाब से ऐनिमेशन

animate*AsState के साथ एक वैल्यू ऐनिमेट करें

animate*AsState फ़ंक्शन, Compose में मौजूद सबसे आसान ऐनिमेशन एपीआई हैं सिंगल वैल्यू को ऐनिमेट करते हैं. आप सिर्फ़ टारगेट या खत्म होने की वैल्यू की जानकारी दें और एपीआई, मौजूदा वैल्यू से बताई गई वैल्यू पर ऐनिमेशन शुरू करता है.

इस एपीआई का इस्तेमाल करके, ऐल्फ़ा वर्शन को ऐनिमेट करने का एक उदाहरण नीचे दिया गया है. खोज बॉक्स में बस रैप करके animateFloatAsState में टारगेट मान, ऐल्फ़ा मान अब एक ऐनिमेशन मान है (इस मामले में 1f या 0.5f) डालें.

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)
)

ध्यान दें कि आपको किसी भी ऐनिमेशन क्लास या हैंडल का इंस्टेंस बनाने की ज़रूरत नहीं है रुकावट. हुड के नीचे, एक ऐनिमेशन ऑब्जेक्ट (जैसे कि Animatable इंस्टेंस) को पहले लक्ष्य के साथ कॉल साइट पर बनाया और याद रखा जाएगा वैल्यू को उसकी शुरुआती वैल्यू के तौर पर सेट करता है. इसके बाद, जब भी इस कंपोज़ेबल को सप्लाई किया जाएगा कोई अलग टारगेट मान नहीं है, तो ऐनिमेशन अपने-आप उस वैल्यू. यदि उड़ान में पहले से कोई ऐनिमेशन है, तो एनिमेशन इसके मौजूदा वैल्यू (और वेलोसिटी) होती है और फिर टारगेट वैल्यू की ओर ऐनिमेट होता है. इस दौरान ऐनिमेशन, इस कंपोज़ेबल को फिर से तैयार किया जाता है और अपडेट किया गया ऐनिमेशन दिखता है मान है.

अलग-अलग फ़ॉर्मैट में, Float के लिए animate*AsState फ़ंक्शन उपलब्ध हैं, Color, Dp, Size, Offset, Rect, Int, IntOffset, और IntSize. अन्य डेटा टाइप के लिए आसानी से सहायता जोड़ी जा सकती है. इसके लिए, TwoWayConverter से animateValueAsState तक, जो सामान्य टाइप में होता है.

AnimationSpec देकर, ऐनिमेशन के स्पेसिफ़िकेशन को पसंद के मुताबिक बनाया जा सकता है. ज़्यादा जानकारी के लिए AnimationSpecification देखें.

ट्रांज़िशन के साथ, एक साथ कई प्रॉपर्टी ऐनिमेट करें

Transition अपने चाइल्ड खाते के तौर पर एक या उससे ज़्यादा ऐनिमेशन मैनेज करता है और उन्हें चलाता है साथ ही, कई राज्यों के लिए एक साथ जनरेट किया जा सकता है.

राज्यों का डेटा टाइप कोई भी हो सकता है. कई मामलों में, आप पसंद के मुताबिक enum का इस्तेमाल कर सकते हैं टाइप की सुरक्षा पक्का करने के लिए, टाइप करें, जैसा कि इस उदाहरण में बताया गया है:

enum class BoxState {
    Collapsed,
    Expanded
}

updateTransition, Transition और अपडेट का एक इंस्टेंस बनाता और याद रखता है उसकी स्थिति है.

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

इसके बाद, किसी चाइल्ड खाते के लिए, animate* एक्सटेंशन फ़ंक्शन में से किसी एक का इस्तेमाल किया जा सकता है ऐनिमेशन दिखाया जा रहा है. हर राज्य के लिए टारगेट वैल्यू तय करें. ये animate* फ़ंक्शन एक ऐनिमेशन वैल्यू दिखाते हैं, जो हर फ़्रेम में अपडेट होती है ऐनिमेशन के दौरान, जब ट्रांज़िशन स्टेट अपडेट हो जाती है 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
    }
}

वैकल्पिक रूप से, आप कोई दूसरा पैरामीटर तय करने के लिए, transitionSpec पैरामीटर पास कर सकते हैं AnimationSpec ट्रांज़िशन की स्थिति में होने वाले बदलावों के हर कॉम्बिनेशन के लिए. यहां जाएं: Animationspec के बारे में ज़्यादा जानें.

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
    }
}

ट्रांज़िशन के टारगेट स्टेटस पर पहुंचने के बाद, Transition.currentState मान Transition.targetState के समान होगा. इसका इस्तेमाल, सिग्नल के तौर पर किया जा सकता है कि ट्रांज़िशन पूरा हो गया है या नहीं.

कभी-कभी हम चाहते हैं कि शुरुआती स्थिति पहले टारगेट से अलग हो राज्य. हम MutableTransitionState के साथ updateTransition का इस्तेमाल करके ये काम कर सकते हैं यह. उदाहरण के लिए, इसकी मदद से हम कोड डालते ही ऐनिमेशन शुरू कर सकते हैं कंपोज़िशन.

// 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")
// ……

ऐप्लिकेशन के कंपोज़ेबल फ़ंक्शन का इस्तेमाल करके ज़्यादा जटिल ट्रांज़िशन पाने के लिए, createChildTransition का इस्तेमाल करें पर क्लिक करें. इस तकनीक की मदद से, समस्याओं को एक कॉम्प्लेक्स कंपोज़ेबल में कई सबकॉम्पोनेंट के बीच में. पैरंट ट्रांज़िशन यह होगा चाइल्ड ट्रांज़िशन में मौजूद सभी ऐनिमेशन वैल्यू के बारे में सजग रहें.

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 और AnimatedContent के साथ ट्रांज़िशन का इस्तेमाल करें

AnimatedVisibility और AnimatedContent Transition के एक्सटेंशन फ़ंक्शन के रूप में उपलब्ध हैं. इसके लिए targetState Transition.AnimatedVisibility और Transition.AnimatedContent को लिया गया है Transition से निकाल दिया जाता है और जब Transition की targetState बदल गई है. ये एक्सटेंशन फ़ंक्शन, सभी enter/exit/sizeTransform ऐनिमेशन को लागू कर सकते हैं जो आम तौर पर AnimatedVisibility/AnimatedContent को Transition में ले जाया जाएगा. इन एक्सटेंशन फ़ंक्शन के साथ, AnimatedVisibility/AnimatedContent की स्थिति बदलाव को बाहर से देखा जा सकता है. बूलियन visible पैरामीटर के बजाय, AnimatedVisibility के इस वर्शन में लैम्डा होता है जो पैरंट को कन्वर्ट करता है ट्रांज़िशन की टारगेट स्टेट को बूलियन में बदल दें.

ज़्यादा जानकारी के लिए, Animated विज़िबिलिटी और AnimatedContent देखें.

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")
            }
        }
    }
}

ट्रांज़िशन को एनकैप्सुलेट करके उसे फिर से इस्तेमाल करने लायक बनाएं

इस्तेमाल के सामान्य उदाहरणों के लिए, ट्रांज़िशन ऐनिमेशन को इस तरह से परिभाषित करना कि वे तो आपका यूज़र इंटरफ़ेस (यूआई) पूरी तरह से मान्य विकल्प है. जब किसी कॉम्प्लेक्स कॉम्पोनेंट पर काम किया जा रहा हो के साथ-साथ आप उन मानों को अलग-अलग कंपोज़ेबल यूज़र इंटरफ़ेस (यूआई) से ऐनिमेशन लागू करना.

ऐसा करने के लिए एक ऐसी क्लास बनाएं जिसमें सभी ऐनिमेशन वैल्यू हों और 'update' फ़ंक्शन है, जो उस क्लास का इंस्टेंस दिखाता है. ट्रांज़िशन लागू करने पर, उसे नए फ़ंक्शन में एक्सट्रैक्ट किया जा सकता है. यह पैटर्न है यह तब काम आता है, जब ऐनिमेशन लॉजिक को सेंट्रलाइज़ करने या मुश्किल बनाने की ज़रूरत हो ऐनिमेशन फिर से इस्तेमाल किए जा सकते हैं.

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 के साथ कभी न खत्म होने वाला ऐनिमेशन बनाएं

InfiniteTransition में Transition जैसे एक या उससे ज़्यादा चाइल्ड ऐनिमेशन हो सकते हैं, लेकिन कंपोज़िशन के अंदर जाते ही ऐनिमेशन चलने लगते हैं और वे तब तक रोक सकते हैं, जब तक उन्हें हटाया न जाए. InfiniteTransition का एक इंस्टेंस बनाया जा सकता है rememberInfiniteTransition के साथ. चाइल्ड ऐनिमेशन जोड़े जा सकते हैं animateColor, animatedFloat या animatedValue. आपको यह भी बताना होगा कि ऐनिमेशन तय करने के लिए infiniteRepable खास जानकारी.

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))

कम लेवल के ऐनिमेशन एपीआई

पिछले सेक्शन में बताए गए सभी हाई-लेवल ऐनिमेशन एपीआई इस पर बनाए गए हैं हम इनमें से किसी एक का इस्तेमाल करते हैं.

animate*AsState फ़ंक्शन सबसे आसान एपीआई हैं, जो एनिमेशन मान के रूप में मान परिवर्तन. यह Animatable की मदद से काम करता है, जो कि कोरूटीन पर आधारित एपीआई की मदद से ऐसा किया जाता है. updateTransition ने बनाया ट्रांज़िशन ऑब्जेक्ट जो कई ऐनिमेशन वैल्यू को मैनेज कर सकता है और उन्हें देश या इलाके में बदलाव हुआ है. rememberInfiniteTransition समान है, लेकिन यह लगातार चलने वाले कई ऐनिमेशन को मैनेज करने वाला इनफ़ाइनाइट ट्रांज़िशन लंबे समय तक. Animatable को छोड़कर, इन सभी एपीआई को कंपोज़ेबल बनाया जा सकता है इसका मतलब है कि इन ऐनिमेशन को कंपोज़िशन के बाहर बनाया जा सकता है.

ये सभी एपीआई, Animation API के सबसे बुनियादी वर्शन पर आधारित हैं. हालांकि ज़्यादातर ऐप्लिकेशन, Animation के साथ सीधे तौर पर इंटरैक्ट नहीं करेंगे. हालांकि, ये ऐप्लिकेशन को पसंद के मुताबिक बनाने के कुछ विकल्प इस्तेमाल किए जाते हैं Animation की क्षमताएं, हाई-लेवल एपीआई के ज़रिए उपलब्ध हैं. यहां जाएं: इस बारे में ज़्यादा जानकारी पाने के लिए, ऐनिमेशन को पसंद के मुताबिक बनाना AnimationVector और AnimationSpec.

लो-लेवल के कई ऐनिमेशन एपीआई के बीच संबंध दिखाने वाला डायग्राम

Animatable: कोरूटीन पर आधारित एक वैल्यू वाला ऐनिमेशन

Animatable ऐसा वैल्यू होल्डर है जो वैल्यू में बदलाव होने पर उसे ऐनिमेट कर सकता है animateTo. यह एपीआई, animate*AsState के लागू करने के तरीके का बैक अप ले रहा है. यह एक समान निरंतरता और पारस्परिक विशिष्टता सुनिश्चित करता है, जिसका अर्थ है कि मान में होने वाला बदलाव हमेशा जारी रहता है और सभी मौजूदा ऐनिमेशन रद्द कर दिए जाएंगे.

Animatable की कई सुविधाएं निलंबित के तौर पर दी गई हैं. इनमें animateTo भी शामिल हैं फ़ंक्शन. इसका मतलब है कि उन्हें सही कोरूटीन में रैप किया जाना चाहिए दायरा. उदाहरण के लिए, LaunchedEffect कंपोज़ेबल का इस्तेमाल करके और सिर्फ़ तय की गई कुंजी वैल्यू की अवधि के लिए स्कोप का इस्तेमाल करें.

// 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))

ऊपर दिए गए उदाहरण में, हम Animatable का एक इंस्टेंस इस तरह बनाते और याद रखते हैं कि Color.Gray की शुरुआती वैल्यू. बूलियन फ़्लैग की वैल्यू के आधार पर ok, रंग Color.Green या Color.Red में ऐनिमेट होता है. कोई भी बाद का बूलियन मान में परिवर्तन करने से एनिमेशन दूसरे रंग से शुरू हो जाता है. अगर कोई लगातार चलने वाला ऐनिमेशन जब वैल्यू बदल जाती है, ऐनिमेशन रद्द हो जाता है, और नया ऐनिमेशन, मौजूदा स्नैपशॉट की वैल्यू और मौजूदा वेलोसिटी से शुरू होता है.

इस ऐनिमेशन को लागू करने की वजह से, animate*AsState एपीआई का बैक अप लिया जाता है जिनका ज़िक्र पिछले सेक्शन में किया गया है. animate*AsState की तुलना में, इसका इस्तेमाल करके Animatable हमें सीधे तौर पर कई मामलों में बेहतर कंट्रोल देता है. सबसे पहले, Animatable की शुरुआती वैल्यू, पहले टारगेट वैल्यू से अलग हो सकती है. उदाहरण के लिए, ऊपर दिया गया कोड उदाहरण शुरू में एक स्लेटी रंग का बॉक्स दिखाता है, जो तुरंत हरे या लाल रंग में ऐनिमेट होना शुरू हो जाता है. दूसरा, Animatable ज़्यादा जानकारी देता है snapTo और animateDecay जैसी कॉन्टेंट वैल्यू पर कार्रवाइयां. snapTo अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है मौजूदा वैल्यू को तुरंत टारगेट वैल्यू पर सेट कर देता है. यह तब फ़ायदेमंद होता है, जब सच्चाई का सिर्फ़ ऐनिमेशन ही नहीं है और उसे दूसरे क्रिएटर्स के साथ सिंक करना पड़ता है स्थितियां, जैसे कि टच इवेंट. animateDecay जिस ऐनिमेशन को शुरू करता है उसकी रफ़्तार धीमी हो जाती है तय किए गए रफ़्तार से. यह फ़्लिंग व्यवहार को लागू करने में मदद करता है. यहां जाएं: ज़्यादा जानकारी के लिए, हाथ के जेस्चर और ऐनिमेशन.

कुल मिलाकर, Animatable Float और Color के साथ काम करता है. हालांकि, किसी भी तरह का डेटा ये काम कर सकता है TwoWayConverter देकर इसका इस्तेमाल किया जा सकता है. यहां जाएं: ज़्यादा जानकारी के लिए Animationvector.

AnimationSpec देकर, ऐनिमेशन की जानकारी को अपनी पसंद के मुताबिक बनाया जा सकता है. ज़्यादा जानकारी के लिए Animationspec देखें.

Animation: मैन्युअल रूप से कंट्रोल किया गया ऐनिमेशन

Animation सबसे कम लेवल वाला ऐनिमेशन एपीआई है. कई ऐनिमेशन वाले हमने देखा है कि अब तक इन-टॉप ऐनिमेशन का इस्तेमाल किया जा रहा है. Animation के दो सब-टाइप हैं: TargetBasedAnimation और DecayAnimation.

Animation का इस्तेमाल सिर्फ़ ऐनिमेशन के समय को मैन्युअल तरीके से कंट्रोल करने के लिए किया जाना चाहिए. Animation स्टेटलेस है. इसमें लाइफ़साइकल का कोई कॉन्सेप्ट नहीं है. यह हाई-लेवल एपीआई इस्तेमाल किए जाने वाले ऐनिमेशन कैलकुलेशन इंजन के तौर पर काम करते हैं.

TargetBasedAnimation

इस्तेमाल के ज़्यादातर मामलों को अन्य एपीआई में शामिल किया जाता है. हालांकि, वे सीधे तौर पर TargetBasedAnimation का इस्तेमाल करते हैं आपको ऐनिमेशन चलाने के समय को खुद कंट्रोल करने की सुविधा मिलती है. नीचे दिए गए उदाहरण में, TargetAnimation के चलने का समय, फ़्रेम के हिसाब से मैन्युअल तरीके से कंट्रोल किया जाता है समय withFrameNanos की ओर से दिया गया.

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 को नापसंद करें, DecayAnimation targetValue देने की ज़रूरत नहीं है. इसके बजाय, यह शुरुआती शर्तों के आधार पर targetValue, जिसे initialVelocity और initialValue और सप्लाई किया गया DecayAnimationSpec.

अक्सर लुप्त होने के निशान वाले ऐनिमेशन का इस्तेमाल अक्सर फ़्लिंग जेस्चर के बाद किया जाता है, ताकि एलिमेंट की रफ़्तार धीमी हो जाए स्टॉप. ऐनिमेशन की वेलोसिटी, initialVelocityVector से सेट की गई वैल्यू से शुरू होती है और यह धीरे-धीरे कम हो जाती है.