মান-ভিত্তিক অ্যানিমেশন

animate*AsState দিয়ে একটি একক মান অ্যানিমেট করুন

animate*AsState ফাংশনগুলি একটি একক মান অ্যানিমেট করার জন্য রচনার সবচেয়ে সহজ অ্যানিমেশন API। আপনি শুধুমাত্র লক্ষ্য মান (বা শেষ মান) প্রদান করেন এবং API বর্তমান মান থেকে নির্দিষ্ট মান পর্যন্ত অ্যানিমেশন শুরু করে।

নিচে এই API ব্যবহার করে আলফা অ্যানিমেটিং করার একটি উদাহরণ দেওয়া হল। animateFloatAsState এ টার্গেট মানটিকে কেবল মোড়ানোর মাধ্যমে, আলফা মান এখন প্রদত্ত মানগুলির মধ্যে একটি অ্যানিমেশন মান (এই ক্ষেত্রে 1f বা 0.5f )।

var enabled by remember { mutableStateOf(true) }

val alpha: Float by animateFloatAsState(if (enabled) 1f else 0.5f, label = "alpha")
Box(
    Modifier
        .fillMaxSize()
        .graphicsLayer(alpha = alpha)
        .background(Color.Red)
)

মনে রাখবেন যে আপনাকে কোনো অ্যানিমেশন ক্লাসের একটি উদাহরণ তৈরি করতে হবে না, বা বাধা হ্যান্ডেল করতে হবে না। হুডের নিচে, একটি অ্যানিমেশন অবজেক্ট (যেমন, একটি Animatable ইনস্ট্যান্স) তৈরি করা হবে এবং কল সাইটে মনে রাখা হবে, যার প্রাথমিক মান হিসাবে প্রথম লক্ষ্য মান। সেখান থেকে, যে কোনো সময় আপনি এই কম্পোজযোগ্য একটি ভিন্ন লক্ষ্য মান সরবরাহ করেন, একটি অ্যানিমেশন স্বয়ংক্রিয়ভাবে সেই মানটির দিকে শুরু হয়। যদি ফ্লাইটে ইতিমধ্যেই একটি অ্যানিমেশন থাকে, তবে অ্যানিমেশনটি তার বর্তমান মান (এবং বেগ) থেকে শুরু হয় এবং লক্ষ্য মানের দিকে অ্যানিমেট হয়। অ্যানিমেশনের সময়, এই কম্পোজেবলটি পুনর্গঠিত হয় এবং প্রতিটি ফ্রেমে একটি আপডেট অ্যানিমেশন মান প্রদান করে।

বাক্সের বাইরে, কম্পোজ 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
    }
}

ঐচ্ছিকভাবে, ট্রানজিশন স্টেট পরিবর্তনের প্রতিটি সংমিশ্রণের জন্য একটি ভিন্ন AnimationSpec নির্দিষ্ট করতে আপনি একটি transitionSpec প্যারামিটার পাস করতে পারেন। আরও তথ্যের জন্য 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 অভ্যন্তরীণ Transition উত্তোলন করতে পারে৷ এই এক্সটেনশন ফাংশনগুলির সাথে, AnimatedVisibility / AnimatedContent অবস্থার পরিবর্তন বাইরে থেকে লক্ষ্য করা যায়। একটি বুলিয়ান visible প্যারামিটারের পরিবর্তে, AnimatedVisibility এই সংস্করণটি একটি ল্যাম্বডা নেয় যা প্যারেন্ট ট্রানজিশনের টার্গেট স্টেটকে বুলিয়ানে রূপান্তর করে।

বিস্তারিত জানার জন্য অ্যানিমেটেড ভিজিবিলিটি এবং অ্যানিমেটেড কনটেন্ট দেখুন।

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")
            }
        }
    }
}

একটি ট্রানজিশন এনক্যাপসুলেট করুন এবং এটি পুনরায় ব্যবহারযোগ্য করুন

সাধারণ ব্যবহারের ক্ষেত্রে, আপনার UI-এর মতো একই কম্পোজেবলে ট্রানজিশন অ্যানিমেশন সংজ্ঞায়িত করা একটি সম্পূর্ণ বৈধ বিকল্প। আপনি যখন বেশ কয়েকটি অ্যানিমেটেড মান সহ একটি জটিল উপাদানে কাজ করছেন, তবে, আপনি কম্পোজযোগ্য UI থেকে অ্যানিমেশন বাস্তবায়নকে আলাদা করতে চাইতে পারেন।

আপনি একটি ক্লাস তৈরি করে এটি করতে পারেন যা সমস্ত অ্যানিমেশন মান ধারণ করে এবং একটি 'আপডেট' ফাংশন যা সেই ক্লাসের একটি উদাহরণ প্রদান করে। রূপান্তর বাস্তবায়ন নতুন পৃথক ফাংশন মধ্যে নিষ্কাশন করা যেতে পারে. যখন অ্যানিমেশন লজিককে কেন্দ্রীভূত করার প্রয়োজন হয় বা জটিল অ্যানিমেশনগুলিকে পুনরায় ব্যবহারযোগ্য করার প্রয়োজন হয় তখন এই প্যাটার্নটি কার্যকর।

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)
)

নিম্ন-স্তরের অ্যানিমেশন API

পূর্ববর্তী বিভাগে উল্লিখিত সমস্ত উচ্চ-স্তরের অ্যানিমেশন APIগুলি নিম্ন-স্তরের অ্যানিমেশন APIগুলির ভিত্তির উপরে নির্মিত।

animate*AsState ফাংশন হল সবচেয়ে সহজ এপিআই, যা একটি অ্যানিমেশন মান হিসাবে তাত্ক্ষণিক মান পরিবর্তন করে। এটি Animatable দ্বারা সমর্থিত, যা একটি একক মান অ্যানিমেট করার জন্য একটি করুটিন-ভিত্তিক API। updateTransition একটি ট্রানজিশন অবজেক্ট তৈরি করে যা একাধিক অ্যানিমেটিং মান পরিচালনা করতে পারে এবং একটি রাষ্ট্র পরিবর্তনের উপর ভিত্তি করে সেগুলি চালাতে পারে। rememberInfiniteTransition অনুরূপ, কিন্তু এটি একটি অসীম রূপান্তর তৈরি করে যা একাধিক অ্যানিমেশন পরিচালনা করতে পারে যা অনির্দিষ্টকালের জন্য চলতে থাকে। Animatable ব্যতীত এই সমস্ত APIগুলিই কম্পোজেবল, যার মানে এই অ্যানিমেশনগুলি রচনার বাইরে তৈরি করা যেতে পারে।

এই সমস্ত APIগুলি আরও মৌলিক Animation API-এর উপর ভিত্তি করে তৈরি৷ যদিও বেশিরভাগ অ্যাপ Animation সাথে সরাসরি ইন্টারঅ্যাক্ট করবে না, Animation জন্য কিছু কাস্টমাইজেশন ক্ষমতা উচ্চ-স্তরের API-এর মাধ্যমে উপলব্ধ। AnimationVector এবং AnimationSpec সম্পর্কে আরও তথ্যের জন্য অ্যানিমেশন কাস্টমাইজ করুন দেখুন।

বিভিন্ন নিম্ন-স্তরের অ্যানিমেশন API-এর মধ্যে সম্পর্ক দেখানো ডায়াগ্রাম

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)
)

উপরের উদাহরণে, আমরা Color.Gray এর প্রারম্ভিক মানের সাথে Animatable একটি উদাহরণ তৈরি এবং মনে রাখি। বুলিয়ান পতাকার মানের উপর নির্ভর করে ok , রঙটি Color.Green বা Color.Red তে অ্যানিমেট হয়। বুলিয়ান মানের পরবর্তী যেকোনো পরিবর্তন অন্য রঙে অ্যানিমেশন শুরু করে। মান পরিবর্তন করার সময় যদি একটি চলমান অ্যানিমেশন থাকে, তবে অ্যানিমেশনটি বাতিল করা হয় এবং নতুন অ্যানিমেশন বর্তমান স্ন্যাপশট মান থেকে বর্তমান বেগের সাথে শুরু হয়।

এটি হল অ্যানিমেশন বাস্তবায়ন যা পূর্ববর্তী বিভাগে উল্লিখিত animate*AsState API-কে ব্যাক আপ করে। animate*AsState এর তুলনায়, Animatable ব্যবহার করে সরাসরি বিভিন্ন বিষয়ে আমাদের সূক্ষ্ম নিয়ন্ত্রণ পাওয়া যায়। প্রথমত, Animatable একটি প্রাথমিক মান তার প্রথম লক্ষ্য মানের থেকে আলাদা হতে পারে। উদাহরণস্বরূপ, উপরের কোড উদাহরণটি প্রথমে একটি ধূসর বাক্স দেখায়, যা অবিলম্বে সবুজ বা লালে অ্যানিমেটিং শুরু করে। দ্বিতীয়ত, Animatable কন্টেন্ট মানের উপর আরও ক্রিয়াকলাপ প্রদান করে, যথা snapTo এবং animateDecaysnapTo অবিলম্বে লক্ষ্য মানের বর্তমান মান সেট করে। এটি কার্যকর যখন অ্যানিমেশন নিজেই সত্যের একমাত্র উৎস নয় এবং অন্যান্য অবস্থার সাথে সিঙ্ক করতে হবে, যেমন স্পর্শ ইভেন্ট। animateDecay একটি অ্যানিমেশন শুরু করে যা প্রদত্ত বেগ থেকে ধীর হয়ে যায়। এটি ফ্লিং আচরণ বাস্তবায়নের জন্য দরকারী। আরও তথ্যের জন্য অঙ্গভঙ্গি এবং অ্যানিমেশন দেখুন।

বাক্সের বাইরে, Animatable Float এবং Color সমর্থন করে, তবে একটি TwoWayConverter প্রদান করে যেকোনো ডেটা টাইপ ব্যবহার করা যেতে পারে। আরও তথ্যের জন্য AnimationVector দেখুন।

আপনি একটি AnimationSpec প্রদান করে অ্যানিমেশন স্পেসিফিকেশন কাস্টমাইজ করতে পারেন। আরও তথ্যের জন্য AnimationSpec দেখুন।

Animation : ম্যানুয়ালি নিয়ন্ত্রিত অ্যানিমেশন

Animation হল সর্বনিম্ন-স্তরের অ্যানিমেশন API উপলব্ধ। আমরা এখন পর্যন্ত অ্যানিমেশনের উপরে তৈরি করা অনেক অ্যানিমেশন দেখেছি। দুটি Animation সাবটাইপ আছে: TargetBasedAnimation এবং DecayAnimation

Animation শুধুমাত্র ম্যানুয়ালি অ্যানিমেশনের সময় নিয়ন্ত্রণ করতে ব্যবহার করা উচিত। Animation রাষ্ট্রহীন, এবং এতে জীবনচক্রের কোনো ধারণা নেই। এটি একটি অ্যানিমেশন গণনা ইঞ্জিন হিসাবে কাজ করে যা উচ্চ-স্তরের API ব্যবহার করে।

TargetBasedAnimation

অন্যান্য API গুলি বেশিরভাগ ব্যবহারের ক্ষেত্রেই কভার করে, কিন্তু TargetBasedAnimation ব্যবহার করলে আপনি নিজে নিজে অ্যানিমেশন খেলার সময় নিয়ন্ত্রণ করতে পারবেন। নীচের উদাহরণে, withFrameNanos দ্বারা প্রদত্ত ফ্রেম সময়ের উপর ভিত্তি করে TargetAnimation খেলার সময় ম্যানুয়ালি নিয়ন্ত্রিত হয়।

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 দ্বারা সেট করা মান থেকে শুরু হয় এবং সময়ের সাথে সাথে ধীর হয়ে যায়।

{% শব্দার্থে %} {% endverbatim %} {% শব্দার্থে %} {% endverbatim %}