Compose में ऐनिमेशन के कई तरीके पहले से मौजूद होते हैं. ऐसे में, यह तय करना मुश्किल हो सकता है कि इनमें से किस तरीके का इस्तेमाल करना है. ऐनिमेशन के इस्तेमाल के सामान्य उदाहरणों की सूची यहां दी गई है. आपके लिए उपलब्ध एपीआई के अलग-अलग विकल्पों के पूरे सेट के बारे में ज़्यादा जानकारी के लिए, ऐनिमेशन बनाने के लिए दस्तावेज़ पढ़ें.
सामान्य कंपोजेबल प्रॉपर्टी को ऐनिमेट करना
Compose में ऐसे एपीआई उपलब्ध होते हैं जिनकी मदद से, ऐनिमेशन के इस्तेमाल के कई सामान्य उदाहरणों को हल किया जा सकता है. इस सेक्शन में, किसी कॉम्पोज़ेबल की सामान्य प्रॉपर्टी को ऐनिमेट करने का तरीका बताया गया है.
ऐनिमेशन के साथ दिखना / छिपना
किसी Composable को छिपाने या दिखाने के लिए, 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
के एंटर और एक्सिट पैरामीटर की मदद से, यह कॉन्फ़िगर किया जा सकता है कि कंपोज़ेबल दिखने और गायब होने पर कैसा व्यवहार करे. ज़्यादा जानकारी के लिए, पूरा दस्तावेज़ पढ़ें.
किसी कॉम्पोज़ेबल की विज़िबिलिटी को ऐनिमेट करने का एक और विकल्प है. इसके लिए, 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 } ) { }
SizeTransform
के साथ AnimatedContent
का इस्तेमाल करके भी, यह बताया जा सकता है कि साइज़ में बदलाव कैसे होने चाहिए.
कॉम्पोज़ेबल की पोज़िशन को ऐनिमेट करना
किसी कॉम्पोज़ेबल की पोज़िशन को ऐनिमेट करने के लिए, 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) ) }
किसी कॉम्पोज़ेबल के पैडिंग को ऐनिमेट करना
किसी कॉम्पोज़ेबल के पैडिंग को ऐनिमेट करने के लिए, 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
कॉम्पोज़ेबल का इस्तेमाल करें और हर स्टेटस के लिए, elevation प्रॉपर्टी को अलग-अलग वैल्यू पर सेट करें.
टेक्स्ट के स्केल, ट्रांसलेशन या रोटेशन को ऐनिमेट करना
टेक्स्ट के स्केल, ट्रांसलेशन या रोटेशन को ऐनिमेट करते समय, textMotion
पैरामीटर को TextStyle
पर 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
को बदलकर, यह तय करें कि पेज को आगे और पीछे कैसे जाना चाहिए.
तय संख्या में दोहराने के लिए, finiteRepeatable
का इस्तेमाल करें.
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
API का इस्तेमाल किया जा सकता है. नीचे दिए गए उदाहरण में, 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 में ऐनिमेशन की वजह से, परफ़ॉर्मेंस से जुड़ी समस्याएं आ सकती हैं. ऐसा इसलिए होता है, क्योंकि ऐनिमेशन की प्रकृति ही ऐसी होती है: इसमें स्क्रीन पर पिक्सल को तेज़ी से, फ़्रेम-दर-फ़्रेम हिलाया या बदला जाता है, ताकि किसी चीज़ के हिलने का भ्रम पैदा किया जा सके.
कॉम्पोज़ करने के अलग-अलग चरणों के बारे में जानें: कॉम्पोज़िशन, लेआउट, और ड्रॉ. अगर आपके ऐनिमेशन से लेआउट फ़ेज़ में बदलाव होता है, तो जिन कॉम्पोज़ेबल पर असर पड़ा है उन्हें फिर से लेआउट करना होगा और फिर से ड्रॉ करना होगा. अगर आपका ऐनिमेशन ड्रॉ फ़ेज़ में होता है, तो डिफ़ॉल्ट रूप से, यह ऐनिमेशन लेआउट फ़ेज़ में चलाने की तुलना में बेहतर परफ़ॉर्म करेगा. इसकी वजह यह है कि इसमें कुल मिलाकर कम काम करना पड़ता है.
ऐनिमेशन के दौरान आपका ऐप्लिकेशन कम से कम काम करे, यह पक्का करने के लिए जहां भी हो सके वहां Modifier
का लैम्ब्डा वर्शन चुनें. यह फिर से कॉम्पोज़ करने की प्रोसेस को छोड़ देता है और कॉम्पोज़ करने के चरण के बाहर ऐनिमेशन करता है. इसके अलावा, Modifier.graphicsLayer{ }
का इस्तेमाल करें, क्योंकि यह मॉडिफ़ायर हमेशा ड्रॉ करने के चरण में चलता है. इस बारे में ज़्यादा जानकारी के लिए, परफ़ॉर्मेंस से जुड़े दस्तावेज़ में रीड को बाद में करने सेक्शन देखें.
ऐनिमेशन की टाइमिंग बदलना
Compose, ज़्यादातर ऐनिमेशन के लिए डिफ़ॉल्ट रूप से स्प्रिंग ऐनिमेशन का इस्तेमाल करता है. स्प्रिंग या फिज़िक्स पर आधारित ऐनिमेशन ज़्यादा नैचुरल लगते हैं. इनमें रुकावट भी आ सकती है, क्योंकि ये किसी तय समय के बजाय, ऑब्जेक्ट के मौजूदा वेग को ध्यान में रखते हैं.
अगर आपको डिफ़ॉल्ट सेटिंग बदलनी है, तो ऊपर दिखाए गए सभी ऐनिमेशन एपीआई में, animationSpec
सेट करने की सुविधा होती है. इससे, ऐनिमेशन के चलने के तरीके को पसंद के मुताबिक बनाया जा सकता है. जैसे, यह तय किया जा सकता है कि ऐनिमेशन को किसी तय समय के लिए चलाया जाए या उसे ज़्यादा बाउंसी बनाया जाए.
animationSpec
के अलग-अलग विकल्पों की खास जानकारी यहां दी गई है:
spring
: फ़िज़िक्स पर आधारित ऐनिमेशन, जो सभी ऐनिमेशन के लिए डिफ़ॉल्ट तौर पर लागू होता है. ऐनिमेशन के अलग-अलग लुक और फ़ील पाने के लिए, stiffness या dampingRatio को बदला जा सकता है.tween
(between का छोटा वर्शन): यह ऐनिमेशन,Easing
फ़ंक्शन की मदद से दो वैल्यू के बीच की अवधि के हिसाब से चलता है.keyframes
: ऐनिमेशन के कुछ अहम पॉइंट पर वैल्यू तय करने के लिए खास जानकारी.repeatable
: यह अवधि पर आधारित स्पेसिफ़िकेशन है, जोRepeatMode
के ज़रिए तय की गई संख्या में चलता है.infiniteRepeatable
: अवधि पर आधारित स्पेसिफ़िकेशन, जो हमेशा चलता रहता है.snap
: बिना किसी ऐनिमेशन के, आखिरी वैल्यू पर तुरंत स्नैप हो जाता है.
animationSpecs के बारे में ज़्यादा जानकारी के लिए, पूरा दस्तावेज़ पढ़ें.
अन्य संसाधन
Compose में मज़ेदार ऐनिमेशन के ज़्यादा उदाहरणों के लिए, यहां देखें:
- Compose में पांच क्विक ऐनिमेशन
- Compose में जेलीफ़िश को हिलाने की सुविधा
- लिखने के लिए इस्तेमाल होने वाले टूल में
AnimatedContent
को पसंद के मुताबिक बनाना - Compose में आसानी से ईज़िंग फ़ंक्शन इस्तेमाल करना