animate*AsState
की मदद से किसी वैल्यू को ऐनिमेट करना
animate*AsState
फ़ंक्शन, Compose में किसी वैल्यू को ऐनिमेट करने के लिए सबसे आसान ऐनिमेशन एपीआई हैं. आपको सिर्फ़ टारगेट वैल्यू (या आखिरी वैल्यू) देनी होती है. इसके बाद, एपीआई, एनिमेशन को मौजूदा वैल्यू से तय की गई वैल्यू तक ले जाता है.
इस एपीआई का इस्तेमाल करके, ऐल्फ़ा को ऐनिमेट करने का उदाहरण यहां दिया गया है. टारगेट वैल्यू को animateFloatAsState
में रैप करने से, ऐल्फ़ा वैल्यू अब दी गई वैल्यू (इस मामले में 1f
या 0.5f
) के बीच की ऐनिमेशन वैल्यू बन जाती है.
var enabled by remember { mutableStateOf(true) } val animatedAlpha: Float by animateFloatAsState(if (enabled) 1f else 0.5f, label = "alpha") Box( Modifier .fillMaxSize() .graphicsLayer { alpha = animatedAlpha } .background(Color.Red) )
ध्यान दें कि आपको किसी भी ऐनिमेशन क्लास का इंस्टेंस बनाने या रुकावट को हैंडल करने की ज़रूरत नहीं है. बैकग्राउंड में, एक ऐनिमेशन ऑब्जेक्ट (यानी कि एक Animatable
instance) बनाया जाएगा और कॉल साइट पर सेव किया जाएगा. इसकी शुरुआती वैल्यू, पहली टारगेट वैल्यू होगी. इसके बाद, जब भी इस कंपोज़ेबल को कोई दूसरी टारगेट वैल्यू दी जाती है, तो उस वैल्यू के लिए ऐनिमेशन अपने-आप शुरू हो जाता है. अगर पहले से कोई ऐनिमेशन चल रहा है, तो ऐनिमेशन अपनी मौजूदा वैल्यू (और वेलोसिटी) से शुरू होता है और टारगेट वैल्यू की ओर ऐनिमेट होता है. ऐनिमेशन के दौरान, यह कंपोज़ेबल फिर से कंपोज़ होता है. साथ ही, हर फ़्रेम में ऐनिमेशन की अपडेट की गई वैल्यू दिखाता है.
Compose में, Float
, Color
, Dp
, Size
, Offset
, Rect
, Int
, IntOffset
, और IntSize
के लिए animate*AsState
फ़ंक्शन उपलब्ध होते हैं. सामान्य टाइप लेने वाले TwoWayConverter
से animateValueAsState
तक, आसानी से अन्य डेटा टाइप के लिए सहायता जोड़ी जा सकती है.
AnimationSpec
देकर, ऐनिमेशन के स्पेसिफ़िकेशन को अपनी पसंद के मुताबिक बनाया जा सकता है.
ज़्यादा जानकारी के लिए, AnimationSpec देखें.
ट्रांज़िशन का इस्तेमाल करके, एक साथ कई प्रॉपर्टी में ऐनिमेशन जोड़ना
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 = rememberTransition(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
के एक्सटेंशन फ़ंक्शन के तौर पर उपलब्ध हैं. Transition.AnimatedVisibility
और Transition.AnimatedContent
के लिए targetState
, Transition
से मिलता है. साथ ही, Transition
के targetState
में बदलाव होने पर, ज़रूरत के मुताबिक ट्रांज़िशन को चालू/बंद करता है. इन एक्सटेंशन फ़ंक्शन की मदद से, AnimatedVisibility
/AnimatedContent
के अंदर मौजूद सभी enter/exit/sizeTransform ऐनिमेशन को Transition
में ले जाया जा सकता है.
इन एक्सटेंशन फ़ंक्शन की मदद से, AnimatedVisibility
/AnimatedContent
के स्टेटस में होने वाले बदलाव को बाहर से देखा जा सकता है. बूलियन visible
पैरामीटर के बजाय, AnimatedVisibility
के इस वर्शन में एक लैम्डा लिया जाता है. यह लैम्डा, पैरंट ट्रांज़िशन की टारगेट स्थिति को बूलियन में बदलता है.
ज़्यादा जानकारी के लिए, AnimatedVisibility और 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), shadowElevation = 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
जैसे एक या एक से ज़्यादा चाइल्ड ऐनिमेशन होते हैं. हालांकि, ये ऐनिमेशन कंपोज़िशन में शामिल होते ही चलने लगते हैं और इन्हें तब तक नहीं रोका जा सकता, जब तक इन्हें हटाया न जाए. rememberInfiniteTransition
की मदद से, InfiniteTransition
का इंस्टेंस बनाया जा सकता है. animateColor
, animatedFloat
या animatedValue
का इस्तेमाल करके, चाइल्ड ऐनिमेशन जोड़े जा सकते हैं. ऐनिमेशन की खास जानकारी देने के लिए, आपको infiniteRepeatable भी तय करना होगा.
val infiniteTransition = rememberInfiniteTransition(label = "infinite") val color by infiniteTransition.animateColor( initialValue = Color.Red, targetValue = Color.Green, animationSpec = infiniteRepeatable( animation = tween(1000, easing = LinearEasing), repeatMode = RepeatMode.Reverse ), label = "color" ) Box( Modifier .fillMaxSize() .background(color) )
लो-लेवल ऐनिमेशन एपीआई
पिछले सेक्शन में बताए गए सभी हाई-लेवल ऐनिमेशन एपीआई, लो-लेवल ऐनिमेशन एपीआई के आधार पर बनाए गए हैं.
animate*AsState
फ़ंक्शन सबसे आसान एपीआई हैं. ये किसी वैल्यू में हुए बदलाव को तुरंत ऐनिमेशन वैल्यू के तौर पर रेंडर करते हैं. यह Animatable
पर आधारित है. यह एक को-रूटीन आधारित एपीआई है, जिसका इस्तेमाल किसी वैल्यू को ऐनिमेट करने के लिए किया जाता है. updateTransition
एक ट्रांज़िशन ऑब्जेक्ट बनाता है. यह ऑब्जेक्ट, ऐनिमेशन वाली कई वैल्यू को मैनेज कर सकता है और उन्हें स्थिति में बदलाव के आधार पर चला सकता है. rememberInfiniteTransition
भी इसी तरह का है. हालांकि, यह एक ऐसा ट्रांज़िशन बनाता है जो कभी खत्म नहीं होता. इससे कई ऐसे ऐनिमेशन मैनेज किए जा सकते हैं जो लगातार चलते रहते हैं. Animatable
को छोड़कर, ये सभी एपीआई कंपोज़ेबल हैं. इसका मतलब है कि इन ऐनिमेशन को कंपोज़िशन के बाहर बनाया जा सकता है.
ये सभी एपीआई, ज़्यादा बुनियादी Animation
एपीआई पर आधारित हैं. ज़्यादातर ऐप्लिकेशन, 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
API के साथ काम करता है. animate*AsState
की तुलना में, Animatable
का सीधे तौर पर इस्तेमाल करने से हमें कई मामलों में बेहतर कंट्रोल मिलता है. पहला,
Animatable
की शुरुआती वैल्यू, पहले टारगेट की वैल्यू से अलग हो सकती है.
उदाहरण के लिए, ऊपर दिए गए कोड के उदाहरण में, शुरुआत में एक ग्रे बॉक्स दिखता है. इसके बाद, यह तुरंत हरे या लाल रंग में ऐनिमेट होना शुरू हो जाता है. दूसरा, Animatable
कॉन्टेंट वैल्यू पर ज़्यादा कार्रवाइयां करने की सुविधा देता है. जैसे, snapTo
और animateDecay
. snapTo
इसकी मदद से, मौजूदा वैल्यू को तुरंत टारगेट वैल्यू पर सेट किया जाता है. यह तब काम आता है, जब ऐनिमेशन ही सच्चाई का एकमात्र सोर्स न हो और उसे टच इवेंट जैसी अन्य स्थितियों के साथ सिंक करना हो. animateDecay
एक ऐसा ऐनिमेशन शुरू करता है जो दी गई वेलोसिटी से धीरे हो जाता है. यह फ़्लिंग के व्यवहार को लागू करने के लिए काम आता है. ज़्यादा जानकारी के लिए, हाव-भाव और ऐनिमेशन देखें.
Animatable
, Float
और Color
के साथ काम करता है. हालांकि, TwoWayConverter
देकर किसी भी डेटा टाइप का इस्तेमाल किया जा सकता है. ज़्यादा जानकारी के लिए, AnimationVector देखें.
AnimationSpec
देकर, ऐनिमेशन के स्पेसिफ़िकेशन को अपनी पसंद के मुताबिक बनाया जा सकता है.
ज़्यादा जानकारी के लिए, AnimationSpec देखें.
Animation
: मैन्युअल तरीके से कंट्रोल किया जाने वाला ऐनिमेशन
Animation
, सबसे कम लेवल वाला Animation API है. अब तक हमने जितने भी ऐनिमेशन देखे हैं उनमें से ज़्यादातर, ऐनिमेशन के ऊपर बनाए गए हैं. 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 { mutableLongStateOf(0L) } LaunchedEffect(anim) { val startTime = withFrameNanos { it } do { playTime = withFrameNanos { it } - startTime val animationValue = anim.getValueFromNanos(playTime) } while (someCustomCondition()) }
DecayAnimation
TargetBasedAnimation
के उलट, DecayAnimation
के लिए targetValue
की वैल्यू देना ज़रूरी नहीं है. इसके बजाय, यह initialVelocity
और initialValue
की सेट की गई शुरुआती शर्तों और दिए गए DecayAnimationSpec
के आधार पर, अपने targetValue
का हिसाब लगाता है.
फ़्लिंग जेस्चर के बाद, अक्सर डेके ऐनिमेशन का इस्तेमाल किया जाता है. इससे एलिमेंट की स्पीड कम हो जाती है और वे रुक जाते हैं. ऐनिमेशन की वेलोसिटी, initialVelocityVector
में सेट की गई वैल्यू से शुरू होती है और समय के साथ कम होती जाती है.
आपके लिए सुझाव
- ध्यान दें: JavaScript बंद होने पर लिंक टेक्स्ट दिखता है
- ऐनिमेशन को पसंद के मुताबिक बनाना {:#customize-animations}
- Compose में ऐनिमेशन
- ऐनिमेशन मॉडिफ़ायर और कंपोज़ेबल