Compose में कई तरह के ऐनिमेशन मैकेनिज़्म पहले से मौजूद होते हैं. ऐसे में, यह तय करना मुश्किल हो सकता है कि कौनसा मैकेनिज़्म चुना जाए. यहां ऐनिमेशन के इस्तेमाल के कुछ सामान्य उदाहरण दिए गए हैं. आपके लिए उपलब्ध अलग-अलग एपीआई विकल्पों के पूरे सेट के बारे में ज़्यादा जानकारी के लिए, Compose ऐनिमेशन का पूरा दस्तावेज़ पढ़ें.
सामान्य कंपोज़ेबल प्रॉपर्टी को ऐनिमेट करना
Compose, इस्तेमाल में आसान एपीआई उपलब्ध कराता है. इनकी मदद से, ऐनिमेशन से जुड़े कई सामान्य मामलों को हल किया जा सकता है. इस सेक्शन में, कंपोज़ेबल की सामान्य प्रॉपर्टी को ऐनिमेट करने का तरीका बताया गया है.
दिखने / गायब होने का ऐनिमेशन
किसी कंपोज़ेबल को छिपाने या दिखाने के लिए, AnimatedVisibility का इस्तेमाल करें. AnimatedVisibility के अंदर मौजूद चाइल्ड व्यू,
एंटर या एग्ज़िट ट्रांज़िशन के लिए
Modifier.animateEnterExit() का इस्तेमाल कर सकते हैं.
var visible by remember { mutableStateOf(true) } // Animated visibility will eventually remove the item from the composition once the animation has finished. AnimatedVisibility(visible) { // your composable here // ... }
AnimatedVisibility के enter और exit पैरामीटर की मदद से, यह कॉन्फ़िगर किया जा सकता है कि कोई कंपोज़ेबल दिखने और गायब होने पर कैसा व्यवहार करे. ज़्यादा जानकारी के लिए, पूरा दस्तावेज़ पढ़ें.
किसी कंपोज़ेबल की विज़िबिलिटी को ऐनिमेट करने का एक और विकल्प है, animateFloatAsState का इस्तेमाल करके समय के साथ ऐल्फ़ा को ऐनिमेट करना:
var visible by remember { mutableStateOf(true) } val animatedAlpha by animateFloatAsState( targetValue = if (visible) 1.0f else 0f, label = "alpha" ) Box( modifier = Modifier .size(200.dp) .graphicsLayer { alpha = animatedAlpha } .clip(RoundedCornerShape(8.dp)) .background(colorGreen) .align(Alignment.TopCenter) ) { }
हालांकि, ऐल्फ़ा वैल्यू बदलने पर, कंपोज़ेबल कंपोज़िशन में बना रहता है और वह अपनी जगह पर बना रहता है. इस वजह से, स्क्रीन रीडर और सुलभता से जुड़ी अन्य सुविधाएं, स्क्रीन पर मौजूद आइटम को अब भी ऐक्सेस कर सकती हैं. वहीं दूसरी ओर, AnimatedVisibility कंपोज़िशन से
आइटम को हटा देता है.
बैकग्राउंड के रंग को ऐनिमेट करना
val animatedColor by animateColorAsState( if (animateBackgroundColor) colorGreen else colorBlue, label = "color" ) Column( modifier = Modifier.drawBehind { drawRect(animatedColor) } ) { // your composable here }
यह विकल्प, Modifier.background() का इस्तेमाल करने से ज़्यादा बेहतर परफ़ॉर्म करता है.
Modifier.background() का इस्तेमाल, एक बार में रंग सेट करने के लिए किया जा सकता है. हालांकि, समय के साथ रंग को ऐनिमेट करने पर, ज़रूरत से ज़्यादा रीकंपोज़िशन हो सकते हैं.
बैकग्राउंड के रंग को लगातार ऐनिमेट करने के लिए, ऐनिमेशन को दोहराना सेक्शन देखें.
किसी कंपोज़ेबल के साइज़ को ऐनिमेट करना
Compose की मदद से, कंपोज़ेबल के साइज़ को अलग-अलग तरीकों से ऐनिमेट किया जा सकता है. कंपोज़ेबल के साइज़ में होने वाले बदलावों के बीच ऐनिमेशन के लिए, animateContentSize() का इस्तेमाल करें.
उदाहरण के लिए, अगर आपके पास कोई ऐसा बॉक्स है जिसमें मौजूद टेक्स्ट को एक से ज़्यादा लाइनों में बढ़ाया जा सकता है, तो Modifier.animateContentSize() का इस्तेमाल करके, ट्रांज़िशन को बेहतर बनाया जा सकता है:
var expanded by remember { mutableStateOf(false) } Box( modifier = Modifier .background(colorBlue) .animateContentSize() .height(if (expanded) 400.dp else 200.dp) .fillMaxWidth() .clickable( interactionSource = remember { MutableInteractionSource() }, indication = null ) { expanded = !expanded } ) { }
AnimatedContent का इस्तेमाल SizeTransform के साथ भी किया जा सकता है, ताकि यह बताया जा सके कि साइज़ में बदलाव कैसे होने चाहिए.
कंपोज़ेबल की पोज़िशन को ऐनिमेट करना
किसी कंपोज़ेबल की पोज़िशन को ऐनिमेट करने के लिए, Modifier.offset{ } के साथ animateIntOffsetAsState() का इस्तेमाल करें.
var moved by remember { mutableStateOf(false) } val pxToMove = with(LocalDensity.current) { 100.dp.toPx().roundToInt() } val offset by animateIntOffsetAsState( targetValue = if (moved) { IntOffset(pxToMove, pxToMove) } else { IntOffset.Zero }, label = "offset" ) Box( modifier = Modifier .offset { offset } .background(colorBlue) .size(100.dp) .clickable( interactionSource = remember { MutableInteractionSource() }, indication = null ) { moved = !moved } )
अगर आपको यह पक्का करना है कि पोज़िशन या साइज़ को ऐनिमेट करते समय, कंपोज़ेबल को अन्य कंपोज़ेबल के ऊपर या नीचे न बनाया जाए, तो Modifier.layout{ } का इस्तेमाल करें. यह मॉडिफ़ायर, साइज़ और पोज़िशन में होने वाले बदलावों को पैरंट कॉम्पोनेंट में लागू करता है. इससे अन्य चाइल्ड कॉम्पोनेंट पर असर पड़ता है.
उदाहरण के लिए, अगर आपको किसी Column में मौजूद Box को मूव करना है और Box के मूव होने पर अन्य चाइल्ड एलिमेंट को भी मूव करना है, तो Modifier.layout{ } के साथ ऑफ़सेट की जानकारी इस तरह शामिल करें:
var toggled by remember { mutableStateOf(false) } val interactionSource = remember { MutableInteractionSource() } Column( modifier = Modifier .padding(16.dp) .fillMaxSize() .clickable(indication = null, interactionSource = interactionSource) { toggled = !toggled } ) { val offsetTarget = if (toggled) { IntOffset(150, 150) } else { IntOffset.Zero } val offset = animateIntOffsetAsState( targetValue = offsetTarget, label = "offset" ) Box( modifier = Modifier .size(100.dp) .background(colorBlue) ) Box( modifier = Modifier .layout { measurable, constraints -> val offsetValue = if (isLookingAhead) offsetTarget else offset.value val placeable = measurable.measure(constraints) layout(placeable.width + offsetValue.x, placeable.height + offsetValue.y) { placeable.placeRelative(offsetValue) } } .size(100.dp) .background(colorGreen) ) Box( modifier = Modifier .size(100.dp) .background(colorBlue) ) }
Modifier.layout{ }कंपोज़ेबल की पैडिंग को ऐनिमेट करना
किसी कंपोज़ेबल की पैडिंग को ऐनिमेट करने के लिए, animateDpAsState के साथ Modifier.padding() का इस्तेमाल करें:
var toggled by remember { mutableStateOf(false) } val animatedPadding by animateDpAsState( if (toggled) { 0.dp } else { 20.dp }, label = "padding" ) Box( modifier = Modifier .aspectRatio(1f) .fillMaxSize() .padding(animatedPadding) .background(Color(0xff53D9A1)) .clickable( interactionSource = remember { MutableInteractionSource() }, indication = null ) { toggled = !toggled } )
किसी कंपोज़ेबल के एलिवेशन को ऐनिमेट करना
किसी कंपोज़ेबल के एलिवेशन को ऐनिमेट करने के लिए, animateDpAsState के साथ Modifier.graphicsLayer{ } का इस्तेमाल करें. एक बार में एलिवेशन में बदलाव करने के लिए, Modifier.shadow() का इस्तेमाल करें. अगर आपको शैडो को ऐनिमेट करना है, तो Modifier.graphicsLayer{ } मॉडिफ़ायर का इस्तेमाल करना बेहतर विकल्प है.
val mutableInteractionSource = remember { MutableInteractionSource() } val pressed = mutableInteractionSource.collectIsPressedAsState() val elevation = animateDpAsState( targetValue = if (pressed.value) { 32.dp } else { 8.dp }, label = "elevation" ) Box( modifier = Modifier .size(100.dp) .align(Alignment.Center) .graphicsLayer { this.shadowElevation = elevation.value.toPx() } .clickable(interactionSource = mutableInteractionSource, indication = null) { } .background(colorGreen) ) { }
इसके अलावा, Card कंपोज़ेबल का इस्तेमाल करें और हर स्टेट के लिए, एलिवेशन प्रॉपर्टी को अलग-अलग वैल्यू पर सेट करें.
टेक्स्ट स्केल, अनुवाद या रोटेशन को ऐनिमेट करना
टेक्स्ट के स्केल, ट्रांसलेशन या रोटेशन को ऐनिमेट करते समय, TextStyle पर textMotion पैरामीटर को TextMotion.Animated पर सेट करें. इससे टेक्स्ट ऐनिमेशन के बीच
ट्रांज़िशन आसान हो जाता है. टेक्स्ट को ट्रांसलेट करने, घुमाने या उसका साइज़ बदलने के लिए, Modifier.graphicsLayer{ } का इस्तेमाल करें.
val infiniteTransition = rememberInfiniteTransition(label = "infinite transition") val scale by infiniteTransition.animateFloat( initialValue = 1f, targetValue = 8f, animationSpec = infiniteRepeatable(tween(1000), RepeatMode.Reverse), label = "scale" ) Box(modifier = Modifier.fillMaxSize()) { Text( text = "Hello", modifier = Modifier .graphicsLayer { scaleX = scale scaleY = scale transformOrigin = TransformOrigin.Center } .align(Alignment.Center), // Text composable does not take TextMotion as a parameter. // Provide it via style argument but make sure that we are copying from current theme style = LocalTextStyle.current.copy(textMotion = TextMotion.Animated) ) }
टेक्स्ट के रंग को ऐनिमेट करना
टेक्स्ट के रंग को ऐनिमेट करने के लिए, BasicText कंपोज़ेबल पर color लैम्ब्डा का इस्तेमाल करें:
val infiniteTransition = rememberInfiniteTransition(label = "infinite transition") val animatedColor by infiniteTransition.animateColor( initialValue = Color(0xFF60DDAD), targetValue = Color(0xFF4285F4), animationSpec = infiniteRepeatable(tween(1000), RepeatMode.Reverse), label = "color" ) BasicText( text = "Hello Compose", color = { animatedColor }, // ... )
अलग-अलग तरह के कॉन्टेंट के बीच स्विच करना
अलग-अलग कंपोज़ेबल के बीच ऐनिमेशन दिखाने के लिए, AnimatedContent का इस्तेमाल करें. अगर आपको कंपोज़ेबल के बीच सिर्फ़ स्टैंडर्ड फ़ेड दिखाना है, तो Crossfade का इस्तेमाल करें.
var state by remember { mutableStateOf(UiState.Loading) } AnimatedContent( state, transitionSpec = { fadeIn( animationSpec = tween(3000) ) togetherWith fadeOut(animationSpec = tween(3000)) }, modifier = Modifier.clickable( interactionSource = remember { MutableInteractionSource() }, indication = null ) { state = when (state) { UiState.Loading -> UiState.Loaded UiState.Loaded -> UiState.Error UiState.Error -> UiState.Loading } }, label = "Animated Content" ) { targetState -> when (targetState) { UiState.Loading -> { LoadingScreen() } UiState.Loaded -> { LoadedScreen() } UiState.Error -> { ErrorScreen() } } }
AnimatedContent को अपनी पसंद के मुताबिक बनाया जा सकता है, ताकि कई तरह के एंटर और एग्ज़िट ट्रांज़िशन दिखाए जा सकें. ज़्यादा जानकारी के लिए, AnimatedContent पर मौजूद दस्तावेज़ पढ़ें या AnimatedContent पर मौजूद यह ब्लॉग पोस्ट पढ़ें.
अलग-अलग डेस्टिनेशन पर नेविगेट करते समय ऐनिमेशन दिखाना
navigation-compose आर्टफ़ैक्ट का इस्तेमाल करते समय, कंपोज़ेबल के बीच ट्रांज़िशन को ऐनिमेट करने के लिए, कंपोज़ेबल पर enterTransition और exitTransition की जानकारी दें. टॉप लेवल NavHost पर, सभी डेस्टिनेशन के लिए इस्तेमाल होने वाला डिफ़ॉल्ट ऐनिमेशन भी सेट किया जा सकता है:
val navController = rememberNavController() NavHost( navController = navController, startDestination = "landing", enterTransition = { EnterTransition.None }, exitTransition = { ExitTransition.None } ) { composable("landing") { ScreenLanding( // ... ) } composable( "detail/{photoUrl}", arguments = listOf(navArgument("photoUrl") { type = NavType.StringType }), enterTransition = { fadeIn( animationSpec = tween( 300, easing = LinearEasing ) ) + slideIntoContainer( animationSpec = tween(300, easing = EaseIn), towards = AnimatedContentTransitionScope.SlideDirection.Start ) }, exitTransition = { fadeOut( animationSpec = tween( 300, easing = LinearEasing ) ) + slideOutOfContainer( animationSpec = tween(300, easing = EaseOut), towards = AnimatedContentTransitionScope.SlideDirection.End ) } ) { backStackEntry -> ScreenDetails( // ... ) } }
एंटर और एग्ज़िट ट्रांज़िशन कई तरह के होते हैं. ये आने वाले और जाने वाले कॉन्टेंट पर अलग-अलग इफ़ेक्ट लागू करते हैं. ज़्यादा जानकारी के लिए, दस्तावेज़ देखें.
किसी ऐनिमेशन को दोहराना
अपने ऐनिमेशन को लगातार दोहराने के लिए, infiniteRepeatable
animationSpec के साथ rememberInfiniteTransition का इस्तेमाल करें. RepeatModes को बदलें, ताकि यह तय किया जा सके कि
यह आगे और पीछे कैसे जाए.
किसी सेट को तय संख्या में दोहराने के लिए, repeatable का इस्तेमाल करें.
val infiniteTransition = rememberInfiniteTransition(label = "infinite") val color by infiniteTransition.animateColor( initialValue = Color.Green, targetValue = Color.Blue, animationSpec = infiniteRepeatable( animation = tween(1000, easing = LinearEasing), repeatMode = RepeatMode.Reverse ), label = "color" ) Column( modifier = Modifier.drawBehind { drawRect(color) } ) { // your composable here }
कंपोज़ेबल के लॉन्च होने पर ऐनिमेशन शुरू करना
LaunchedEffect तब चलता है, जब कोई कंपोज़ेबल, कंपोज़िशन में शामिल होता है. यह कंपोज़ेबल के लॉन्च होने पर ऐनिमेशन शुरू करता है. इसका इस्तेमाल, ऐनिमेशन की स्थिति में बदलाव करने के लिए किया जा सकता है. लॉन्च के समय ऐनिमेशन शुरू करने के लिए, animateTo तरीके के साथ Animatable का इस्तेमाल करना:
val alphaAnimation = remember { Animatable(0f) } LaunchedEffect(Unit) { alphaAnimation.animateTo(1f) } Box( modifier = Modifier.graphicsLayer { alpha = alphaAnimation.value } )
क्रम में चलने वाले ऐनिमेशन बनाना
क्रम में या एक साथ चलने वाले ऐनिमेशन बनाने के लिए, Animatable कोरूटीन एपीआई का इस्तेमाल करें. Animatable पर animateTo को एक के बाद एक कॉल करने से, हर ऐनिमेशन को आगे बढ़ने से पहले, पिछले ऐनिमेशन के खत्म होने का इंतज़ार करना पड़ता है.
ऐसा इसलिए है, क्योंकि यह एक सस्पेंड फ़ंक्शन है.
val alphaAnimation = remember { Animatable(0f) } val yAnimation = remember { Animatable(0f) } LaunchedEffect("animationKey") { alphaAnimation.animateTo(1f) yAnimation.animateTo(100f) yAnimation.animateTo(500f, animationSpec = tween(100)) }
एक साथ कई ऐनिमेशन बनाना
एक साथ कई ऐनिमेशन चलाने के लिए, कोरूटीन एपीआई (Animatable#animateTo() या animate) या Transition एपीआई का इस्तेमाल करें. अगर कोरूटीन कॉन्टेक्स्ट में कई लॉन्च फ़ंक्शन इस्तेमाल किए जाते हैं, तो यह ऐनिमेशन एक साथ लॉन्च करता है:
val alphaAnimation = remember { Animatable(0f) } val yAnimation = remember { Animatable(0f) } LaunchedEffect("animationKey") { launch { alphaAnimation.animateTo(1f) } launch { yAnimation.animateTo(100f) } }
updateTransition एपीआई का इस्तेमाल करके, एक ही स्टेट का इस्तेमाल करके एक ही समय पर कई अलग-अलग प्रॉपर्टी ऐनिमेशन चलाए जा सकते हैं. इस उदाहरण में, स्थिति में बदलाव करके कंट्रोल की जाने वाली दो प्रॉपर्टी को ऐनिमेट किया गया है. ये प्रॉपर्टी हैं: rect और borderWidth:
var currentState by remember { mutableStateOf(BoxState.Collapsed) } val transition = updateTransition(currentState, label = "transition") val rect by transition.animateRect(label = "rect") { state -> when (state) { BoxState.Collapsed -> Rect(0f, 0f, 100f, 100f) BoxState.Expanded -> Rect(100f, 100f, 300f, 300f) } } val borderWidth by transition.animateDp(label = "borderWidth") { state -> when (state) { BoxState.Collapsed -> 1.dp BoxState.Expanded -> 0.dp } }
एनिमेशन की परफ़ॉर्मेंस को ऑप्टिमाइज़ करना
Compose में ऐनिमेशन की वजह से, परफ़ॉर्मेंस से जुड़ी समस्याएं आ सकती हैं. ऐसा ऐनिमेशन की प्रकृति की वजह से होता है: स्क्रीन पर पिक्सल को तेज़ी से मूव करना या बदलना, फ़्रेम-दर-फ़्रेम, ताकि मूवमेंट का भ्रम पैदा किया जा सके.
Compose के अलग-अलग फ़ेज़ को ध्यान में रखें: कंपोज़िशन, लेआउट, और ड्रॉ. अगर आपका ऐनिमेशन, लेआउट फ़ेज़ में बदलाव करता है, तो इससे जिन कंपोज़ेबल पर असर पड़ा है उन्हें फिर से लेआउट और ड्रॉ करना होगा. अगर आपका ऐनिमेशन ड्रॉ फ़ेज़ में होता है, तो यह डिफ़ॉल्ट रूप से ज़्यादा परफ़ॉर्म करता है. ऐसा तब होता है, जब आपको लेआउट फ़ेज़ में ऐनिमेशन चलाना हो, क्योंकि इसमें कुल मिलाकर कम काम करना होगा.
ऐनिमेशन के दौरान आपका ऐप्लिकेशन कम से कम काम करे, इसके लिए जहां भी संभव हो Modifier का लैम्डा वर्शन चुनें. यह रीकंपोज़िशन को स्किप करता है और कंपोज़िशन फ़ेज़ के बाहर ऐनिमेशन को चलाता है. इसके अलावा, Modifier.graphicsLayer{ } का इस्तेमाल करें, क्योंकि यह मॉडिफ़ायर हमेशा ड्रॉ फ़ेज़ में चलता है. इस बारे में ज़्यादा जानने के लिए, परफ़ॉर्मेंस से जुड़े दस्तावेज़ में रीड को बाद में करने वाला सेक्शन देखें.
ऐनिमेशन की टाइमिंग बदलना
Compose, ज़्यादातर ऐनिमेशन के लिए डिफ़ॉल्ट रूप से स्प्रिंग ऐनिमेशन का इस्तेमाल करता है. स्प्रिंग या फ़िज़िक्स पर आधारित ऐनिमेशन, ज़्यादा नैचुरल लगते हैं. इन्हें रोका भी जा सकता है, क्योंकि ये किसी तय समय के बजाय, ऑब्जेक्ट की मौजूदा वेलोसिटी को ध्यान में रखते हैं.
अगर आपको डिफ़ॉल्ट सेटिंग को बदलना है, तो पहले दिखाए गए सभी Animation API में animationSpec सेट करने की सुविधा होती है. इससे, ऐनिमेशन के चलने के तरीके को पसंद के मुताबिक बनाया जा सकता है. भले ही, आपको उसे किसी खास अवधि के लिए चलाना हो या ज़्यादा बाउंस करना हो.
animationSpec के अलग-अलग विकल्पों की खास जानकारी यहां दी गई है:
spring: फ़िज़िक्स पर आधारित ऐनिमेशन, जो सभी ऐनिमेशन के लिए डिफ़ॉल्ट होता है. ऐनिमेशन को अलग लुक और स्टाइल देने के लिए, स्टिफ़नेस या dampingRatio में बदलाव किया जा सकता है.tween(between का छोटा रूप): अवधि के हिसाब से ऐनिमेशन,Easingफ़ंक्शन की मदद से दो वैल्यू के बीच ऐनिमेशन दिखाता है.keyframes: ऐनिमेशन में कुछ मुख्य पॉइंट पर वैल्यू तय करने के लिए खास जानकारी.repeatable: यह अवधि के हिसाब से तय की गई शर्त है. इसके तहत, कोई कार्रवाई तय संख्या में की जाती है. यह संख्याRepeatModeसे तय होती है.infiniteRepeatable: अवधि के हिसाब से तय की गई ऐसी शर्त जो हमेशा लागू रहती है.snap: बिना किसी ऐनिमेशन के, तुरंत आखिरी वैल्यू पर स्नैप करता है.
animationSpecs के बारे में ज़्यादा जानने के लिए, पूरा दस्तावेज़ पढ़ें.
अन्य संसाधन
Compose में मज़ेदार ऐनिमेशन के और उदाहरण देखने के लिए, यहां जाएं:
- Compose में पांच क्विक ऐनिमेशन
- Compose में जेलीफ़िश को मूव करना
- Compose में
AnimatedContentको पसंद के मुताबिक बनाना - Compose में ईज़िंग फ़ंक्शन के बारे में जानकारी