Compose-এ অ্যানিমেশন সম্পর্কে সংক্ষিপ্ত নির্দেশিকা

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

সাধারণ কম্পোজ করার উপযুক্ত প্রপার্টি অ্যানিমেট করা

Compose এমন API প্রদান করে যা আপনাকে অনেক সাধারণ অ্যানিমেশন ব্যবহারের ক্ষেত্রে সমাধান করতে সাহায্য করে। এই বিভাগে কীভাবে কম্পোজ করার উপযুক্ত আইটেমের সাধারণ প্রপার্টি অ্যানিমেট করতে হয় তা দেখানো হয়েছে।

দৃশ্যমান / অদৃশ্যমান হওয়ার অ্যানিমেশন

সবুজ কম্পোজ করার মতো আইটেম নিজে থেকেই দেখা ও লুকানো
ছবি ১. Column
-এ কোনও আইটেমের দৃশ্যমান হওয়া ও অদৃশ্য হয়ে যাওয়া অ্যানিমেট করা

কোনও কম্পোজ করার উপযুক্ত আইটেম লুকাতে বা দেখাতে 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
        }

) {
}

এছাড়াও, সাইজ কীভাবে পরিবর্তন করা উচিত তা বর্ণনা করতে, আপনি 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)
    )
}

২টি বক্স, ২য় বক্সটি তার X,Y পজিশন অ্যানিমেট করছে, ৩য় বক্সটি Y পরিমাণ মতো নিজেকে সরিয়ে নিয়ে উত্তর দিচ্ছে।
ছবি ৬. 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 ব্যবহার করা (ধীর গতিতে)

আপনি যদি কম্পোজ করার উপযুক্ত আইটেমগুলির মধ্যে অ্যানিমেট করতে চান, তাহলে 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 ব্যবহার করে কম্পোজ করার উপযুক্ত আইটেমের মধ্যে অ্যানিমেট করা

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(
            // ...
        )
    }
}

এন্ট্রি ও এক্সিট ট্রানজিশনের অনেক আলাদা আলাদা ধরন আছে যা ইনকামিং ও আউটগোয়িং কন্টেন্টে আলাদা আলাদা এফেক্ট প্রয়োগ করে, আরও জানতে ডকুমেন্টেশন দেখুন।

অ্যানিমেশন রিপিট করা

একটি সবুজ ব্যাকগ্রাউন্ড যা দুটি রঙের মধ্যে অ্যানিমেট করার মাধ্যমে অসীমভাবে নীল ব্যাকগ্রাউন্ডে রূপান্তরিত হয়।
ছবি ১৩. দুটি ভ্যালুর মধ্যে ব্যাকগ্রাউন্ড কালার অ্যানিমেট করা হচ্ছে, অসীম

আপনার অ্যানিমেশন একটানা রিপিট করতে rememberInfiniteTransition-এর সাথে infiniteRepeatable animationSpec ব্যবহার করুন। এটি কীভাবে সামনে-পিছনে যাবে তা নির্দিষ্ট করতে 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 করুটিন 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))
}

কনকারেন্ট অ্যানিমেশন তৈরি করা

তিনটি বৃত্তের প্রত্যেকটিতে সবুজ তীরচিহ্ন অ্যানিমেট করছে, একই সাথে সবগুলি একসাথে অ্যানিমেট করছে।
ছবি ১৫. একই সময়ে একাধিক অ্যানিমেশন কীভাবে প্রোগ্রেস করে তা ডায়াগ্রামে দেখানো হয়েছে।

একসাথে অ্যানিমেশন চালানোর জন্য, কোরাউটিন API (Animatable#animateTo() বা animate) অথবা Transition API ব্যবহার করুন। আপনি কোরাউটিন কনটেক্সটে একাধিক লঞ্চ ফাংশন ব্যবহার করলে, এটি একই সময়ে অ্যানিমেশন লঞ্চ করে:

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 ডিফল্ট হিসেবে বেশিরভাগ অ্যানিমেশনের জন্য স্প্রিং অ্যানিমেশন ব্যবহার করে। স্প্রিং বা পদার্থবিদ্যা-ভিত্তিক অ্যানিমেশন আরও স্বাভাবিক মনে হয়। এছাড়াও, এগুলি বাধা দেওয়া যায় কারণ এগুলি নির্দিষ্ট সময়ের পরিবর্তে অবজেক্টের বর্তমান বেগ বিবেচনা করে। আপনি ডিফল্ট ওভাররাইড করতে চাইলে, আগে দেখানো সব অ্যানিমেশন API-তে অ্যানিমেশন কীভাবে চলবে তা কাস্টমাইজ করার জন্য animationSpec সেট করার ক্ষমতা আছে। আপনি কি চান যে এটি একটি নির্দিষ্ট সময় ধরে এক্সিকিউট হোক নাকি আরও বেশি বাউন্সি হোক।

বিভিন্ন animationSpec বিকল্পের সারসংক্ষেপ নিচে দেওয়া হল:

  • spring: পদার্থবিদ্যা-ভিত্তিক অ্যানিমেশন, সব অ্যানিমেশনের জন্য ডিফল্ট। আপনি স্টিফনেস বা ড্যাম্পিং রেশিও পরিবর্তন করে অন্য ধরনের অ্যানিমেশন লুক অ্যান্ড ফিল পেতে পারেন।
  • tween (বিটুইন-এর সংক্ষিপ্ত রূপ): সময়সীমা-ভিত্তিক অ্যানিমেশন, Easing ফাংশনের সাহায্যে দুটি ভ্যালুর মধ্যে অ্যানিমেট করে।
  • keyframes: কোনও অ্যানিমেশনের নির্দিষ্ট কী পয়েন্টে ভ্যালু নির্দিষ্ট করার স্পেক।
  • repeatable: সময়সীমা-ভিত্তিক স্পেক যা RepeatMode-এর নির্দিষ্ট করা, নির্দিষ্ট সংখ্যক বার চলে।
  • infiniteRepeatable: অনির্দিষ্টকালের জন্য চলতে থাকা সময়সীমা-ভিত্তিক স্পেক।
  • snap: কোনও অ্যানিমেশন ছাড়াই শেষ ভ্যালুতে সঙ্গে সঙ্গে স্ন্যাপ করে।
দুটি অ্যানিমেশন, একটিতে কোনও স্পেক সেট করা নেই এবং অন্যটিতে কাস্টম স্প্রিং স্পেক সেট করা আছে।
ছবি ১৬. কোনও স্পেক সেট করা নেই বনাম কাস্টম স্প্রিং স্পেক সেট করা আছে

animationSpecs সম্পর্কে আরও তথ্য পেতে সম্পূর্ণ ডকুমেন্টেশন পড়ুন।

অতিরিক্ত রিসোর্স

Compose-এ মজাদার অ্যানিমেশনের আরও উদাহরণ দেখতে, নিম্নলিখিত বিষয়গুলি দেখুন: