Compose-এ অনেকগুলো বিল্ট-ইন অ্যানিমেশন মেকানিজম রয়েছে এবং এর মধ্যে কোনটি বেছে নেবেন তা ঠিক করা বেশ কঠিন হতে পারে। নিচে সাধারণ কিছু অ্যানিমেশন ব্যবহারের উদাহরণের একটি তালিকা দেওয়া হলো। আপনার জন্য উপলব্ধ বিভিন্ন API অপশনগুলোর সম্পূর্ণ সেট সম্পর্কে আরও বিস্তারিত তথ্যের জন্য, Compose Animation-এর সম্পূর্ণ ডকুমেন্টেশনটি পড়ুন।
সাধারণ রচনাযোগ্য বৈশিষ্ট্যগুলিকে অ্যানিমেট করুন
Compose সুবিধাজনক API প্রদান করে, যার মাধ্যমে আপনি অ্যানিমেশনের অনেক সাধারণ সমস্যার সমাধান করতে পারেন। এই বিভাগে দেখানো হয়েছে, কীভাবে একটি কম্পোজেবলের সাধারণ প্রোপার্টিগুলোকে অ্যানিমেট করা যায়।
অ্যানিমেট করে আবির্ভূত / অদৃশ্য হওয়া

একটি 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 এর 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 রান করে। এটি একটি কম্পোজেবল চালু হওয়ার সাথে সাথে একটি অ্যানিমেশন শুরু করে, আপনি অ্যানিমেশনের অবস্থার পরিবর্তন নিয়ন্ত্রণ করতে এটি ব্যবহার করতে পারেন। চালু হওয়ার সাথে সাথে অ্যানিমেশন শুরু করতে Animatable এর সাথে animateTo মেথড ব্যবহার করার পদ্ধতি:
val alphaAnimation = remember { Animatable(0f) } LaunchedEffect(Unit) { alphaAnimation.animateTo(1f) } Box( modifier = Modifier.graphicsLayer { alpha = alphaAnimation.value } )
ক্রমিক অ্যানিমেশন তৈরি করুন

ক্রমিক বা যুগপৎ অ্যানিমেশন সম্পাদন করতে Animatable কো-রুটিন API ব্যবহার করুন। 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 } }
অ্যানিমেশন পারফরম্যান্স অপ্টিমাইজ করুন
কম্পোজ-এর অ্যানিমেশন পারফরম্যান্সের সমস্যা সৃষ্টি করতে পারে। এর কারণ হলো অ্যানিমেশনের প্রকৃতিই এমন: এটি নড়াচড়ার বিভ্রম তৈরি করার জন্য স্ক্রিনের পিক্সেলগুলোকে দ্রুত, ফ্রেম-বাই-ফ্রেম সরানো বা পরিবর্তন করে।
কম্পোজ-এর বিভিন্ন পর্যায়গুলো বিবেচনা করুন: কম্পোজিশন, লেআউট এবং ড্র। যদি আপনার অ্যানিমেশন লেআউট পর্যায় পরিবর্তন করে, তবে এর দ্বারা প্রভাবিত সমস্ত কম্পোজেবলকে পুনরায় লেআউট এবং পুনরায় ড্র করতে হয়। যদি আপনার অ্যানিমেশন ড্র পর্যায়ে ঘটে, তবে এটি লেআউট পর্যায়ে চালানোর চেয়ে স্বাভাবিকভাবেই বেশি পারফর্ম্যান্ট হবে, কারণ সেক্ষেত্রে সামগ্রিকভাবে এর কাজ কম থাকে।
অ্যানিমেট করার সময় আপনার অ্যাপ যাতে যথাসম্ভব কম কাজ করে, তা নিশ্চিত করতে যেখানে সম্ভব Modifier ল্যাম্বডা সংস্করণটি বেছে নিন। এটি রিকম্পোজিশন এড়িয়ে যায় এবং কম্পোজিশন পর্বের বাইরে অ্যানিমেশনটি সম্পাদন করে, অন্যথায় Modifier.graphicsLayer{ } ব্যবহার করুন, কারণ এই মডিফায়ারটি সর্বদা ড্র পর্বে চলে। এই বিষয়ে আরও তথ্যের জন্য, পারফরম্যান্স ডকুমেন্টেশনের ডিফারিং রিডস বিভাগটি দেখুন।
অ্যানিমেশনের সময় পরিবর্তন করুন
কম্পোজ ডিফল্টভাবে বেশিরভাগ অ্যানিমেশনের জন্য স্প্রিং অ্যানিমেশন ব্যবহার করে। স্প্রিং বা পদার্থবিদ্যা-ভিত্তিক অ্যানিমেশনগুলো আরও স্বাভাবিক মনে হয়। এগুলোকে থামানোও যায়, কারণ এগুলো একটি নির্দিষ্ট সময়ের পরিবর্তে অবজেক্টের বর্তমান বেগ বিবেচনা করে। আপনি যদি ডিফল্টটি পরিবর্তন করতে চান, তবে উপরে দেখানো সমস্ত অ্যানিমেশন এপিআই-তেই একটি animationSpec সেট করার সুবিধা রয়েছে। এর মাধ্যমে আপনি অ্যানিমেশনটি কীভাবে চলবে তা কাস্টমাইজ করতে পারেন, যেমন—আপনি এটিকে একটি নির্দিষ্ট সময় ধরে চালাতে চান নাকি আরও বাউন্সি (bouncey) করতে চান।
নিম্নলিখিতটি হলো বিভিন্ন animationSpec অপশনগুলোর সারসংক্ষেপ:
-
spring: পদার্থবিদ্যা-ভিত্তিক অ্যানিমেশন, যা সকল অ্যানিমেশনের জন্য ডিফল্ট। ভিন্ন ধরনের অ্যানিমেশন লুক ও ফিল আনার জন্য আপনি স্টিফনেস বা ড্যাম্পিং রেশিও পরিবর্তন করতে পারেন। -
tween( বিটুইন -এর সংক্ষিপ্ত রূপ): সময়কাল-ভিত্তিক অ্যানিমেশন, যা একটিEasingফাংশনের সাহায্যে দুটি মানের মধ্যে অ্যানিমেশন পরিবর্তন করে। -
keyframes: কোনো অ্যানিমেশনের নির্দিষ্ট গুরুত্বপূর্ণ মুহূর্তে মান নির্ধারণের জন্য ব্যবহৃত স্পেসিফিকেশন। -
repeatable: সময়কাল-ভিত্তিক স্পেসিফিকেশন যা একটি নির্দিষ্ট সংখ্যক বার চলে, এবং যাRepeatModeদ্বারা নির্দিষ্ট করা হয়। -
infiniteRepeatable: সময়কাল-ভিত্তিক স্পেক যা অনির্দিষ্টকাল ধরে চলতে থাকে। -
snap: কোনো অ্যানিমেশন ছাড়াই তাৎক্ষণিকভাবে শেষ মানে চলে যায়।

animationSpecs সম্পর্কে আরও তথ্যের জন্য সম্পূর্ণ ডকুমেন্টেশন পড়ুন।
অতিরিক্ত সম্পদ
কম্পোজে আরও মজার অ্যানিমেশনের উদাহরণ দেখতে নিচেরগুলো দেখুন:
- কম্পোজে ৫টি দ্রুত অ্যানিমেশন
- কম্পোজে জেলিফিশকে নড়াচড়া করানো
- কম্পোজে
AnimatedContentকাস্টমাইজ করা - Compose-এ Easing ফাংশনগুলিতে সহজে প্রবেশ করা