اصلاح‌کننده‌های پویانمایی و عناصر ترکیبی

‫Compose با تابع‌های ترکیب‌پذیر و اصلاح‌گرهای داخلی برای مدیریت موارد استفاده رایج پویانمایی ارائه می‌شود.

عناصر ترکیبی پویانمایی‌شده داخلی

‫Compose چندین عنصر ترکیبی ارائه می‌دهد که ظاهر محتوا، ناپدید شدن، و تغییرات چیدمان را پویانمایی می‌کنند.

پویانمایی ظاهر و ناپدید شدن

عنصر ترکیبی سبز که خود را نشان می‌دهد و پنهان می‌کند
شکل ۱. پویانمایی ظاهر و ناپدید شدن موردی در ستون.

این AnimatedVisibility عنصر ترکیبی ظاهر و ناپدید شدن محتوایش را پویانمایی می‌کند.

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

به‌طور پیش‌فرض، محتوا با محو شدن و گسترش ظاهر می‌شود و با محو شدن و کوچک شدن ناپدید می‌شود. با مشخص کردن EnterTransition و ExitTransition اشیا، این گذار را سفارشی‌سازی کنید.

var visible by remember { mutableStateOf(true) }
val density = LocalDensity.current
AnimatedVisibility(
    visible = visible,
    enter = slideInVertically {
        // Slide in from 40 dp from the top.
        with(density) { -40.dp.roundToPx() }
    } + expandVertically(
        // Expand from the top.
        expandFrom = Alignment.Top
    ) + fadeIn(
        // Fade in with the initial alpha of 0.3f.
        initialAlpha = 0.3f
    ),
    exit = slideOutVertically() + shrinkVertically() + fadeOut()
) {
    Text(
        "Hello",
        Modifier
            .fillMaxWidth()
            .height(200.dp)
    )
}

همان‌طور که در مثال قبلی نشان داده شده است، می‌توانید چندین EnterTransition یا ExitTransition شیء را با یک عامل + ترکیب کنید، و هرکدام از آن‌ها پارامترهای اختیاری را برای سفارشی‌سازی رفتارشان می‌پذیرند. برای اطلاعات بیشتر، به صفحه‌های مرجع مراجعه کنید.

نمونه‌های گذار ورود و خروج

EnterTransition ExitTransition
fadeIn
عنصر میانای کاربر به‌تدریج در دید محو می‌شود.
fadeOut
عنصر میانای کاربر به‌تدریج از دید محو می‌شود.
slideIn
عنصر واسط کاربر از خارج از صفحه به داخل صفحه می‌لغزد.
slideOut
عنصر واسط کاربر از نمای خارج از صفحه می‌لغزد.
slideInHorizontally
عنصر میانای کاربر به‌صورت افقی به داخل نما می‌لغزد.
slideOutHorizontally
عنصر میانای کاربر به‌صورت افقی از دید خارج می‌شود.
slideInVertically
عنصر میانای کاربر به‌صورت عمودی به داخل نما می‌لغزد.
slideOutVertically
عنصر میانای کاربر به‌صورت عمودی از دید خارج می‌شود.
scaleIn
عنصر میانای کاربر بزرگ می‌شود و به نمای دید می‌آید.
scaleOut
عنصر میانای کاربر کوچک می‌شود و از دید خارج می‌شود.
expandIn
عنصر میانای کاربری از یک نقطه مرکزی به نمای باز می‌شود.
shrinkOut
عنصر میانای کاربری از دید کوچک می‌شود و به نقطه مرکزی می‌رسد.
expandHorizontally
عنصر میانای کاربر به‌صورت افقی ازهم باز می‌شود و در نما قرار می‌گیرد.
shrinkHorizontally
عنصر میانای کاربر به‌صورت افقی از دید کوچک می‌شود.
expandVertically
عنصر میانای کاربر به‌صورت عمودی در نما ازهم باز می‌شود.
shrinkVertically
عنصر واسط کاربر به‌صورت عمودی از دید کوچک می‌شود.

‫AnimatedVisibility همچنین گونه‌ای ارائه می‌دهد که MutableTransitionState متغیر مستقل می‌گیرد. این کار به شما امکان می‌دهد پویانمایی را به‌محض اینکه عنصر AnimatedVisibility ترکیبی به درخت ترکیب اضافه شد راه‌اندازی کنید. همچنین برای مشاهده وضعیت پویانمایی مفید است.

// Create a MutableTransitionState<Boolean> for the AnimatedVisibility.
val state = remember {
    MutableTransitionState(false).apply {
        // Start the animation immediately.
        targetState = true
    }
}
Column {
    AnimatedVisibility(visibleState = state) {
        Text(text = "Hello, world!")
    }

    // Use the MutableTransitionState to know the current animation state
    // of the AnimatedVisibility.
    Text(
        text = when {
            state.isIdle && state.currentState -> "Visible"
            !state.isIdle && state.currentState -> "Disappearing"
            state.isIdle && !state.currentState -> "Invisible"
            else -> "Appearing"
        }
    )
}

پویانمایی ورود و خروج برای کودکان

محتوای درون AnimatedVisibility (فرزندان مستقیم یا غیرمستقیم) می‌تواند از animateEnterExit اصلاح‌گر برای مشخص کردن رفتار پویانمایی متفاوت برای هریک از آن‌ها استفاده کند. جلوه دیداری برای هریک از این فرزندان ترکیبی از پویانمایی‌های مشخص‌شده در AnimatedVisibility ترکیب‌شدنی و پویانمایی‌های ورود و خروج فرزند است.

var visible by remember { mutableStateOf(true) }

AnimatedVisibility(
    visible = visible,
    enter = fadeIn(),
    exit = fadeOut()
) {
    // Fade in/out the background and the foreground.
    Box(
        Modifier
            .fillMaxSize()
            .background(Color.DarkGray)
    ) {
        Box(
            Modifier
                .align(Alignment.Center)
                .animateEnterExit(
                    // Slide in/out the inner box.
                    enter = slideInVertically(),
                    exit = slideOutVertically()
                )
                .sizeIn(minWidth = 256.dp, minHeight = 64.dp)
                .background(Color.Red)
        ) {
            // Content of the notification…
        }
    }
}

در برخی موارد، ممکن است بخواهید AnimatedVisibility هیچ پویانمایی‌ای اعمال نکند تا کودکان بتوانند هرکدام پویانمایی‌های متمایز خودشان را با animateEnterExit داشته باشند. برای دستیابی به این هدف، EnterTransition.None و ExitTransition.None را در عنصر ترکیبی AnimatedVisibility مشخص کنید.

افزودن پویانمایی سفارشی

اگر می‌خواهید جلوه‌های پویانمایی سفارشی فراتر از پویانمایی‌های ورود و خروج داخلی اضافه کنید، بااستفاده از دارایی transition در لامبدای محتوا برای AnimatedVisibility، به نمونه Transition زیرین دسترسی پیدا کنید. هر حالت پویانمایی اضافه‌شده به نمونه «گذار» به‌طور هم‌زمان با پویانمایی‌های ورود و خروج AnimatedVisibility اجرا خواهد شد. AnimatedVisibility منتظر می‌ماند تا همه پویانمایی‌های Transition تمام شود و سپس محتوای آن را برمی‌دارد. برای پویانمایی‌های خروجی که به‌طور مستقل از Transition ایجاد شده‌اند (مثلاً بااستفاده از animate*AsState)، AnimatedVisibility نمی‌تواند آن‌ها را درنظر بگیرد، و بنابراین ممکن است عنصر ترکیبی محتوا را قبل‌از پایان یافتن آن‌ها بردارد.

var visible by remember { mutableStateOf(true) }

AnimatedVisibility(
    visible = visible,
    enter = fadeIn(),
    exit = fadeOut()
) { // this: AnimatedVisibilityScope
    // Use AnimatedVisibilityScope#transition to add a custom animation
    // to the AnimatedVisibility.
    val background by transition.animateColor(label = "color") { state ->
        if (state == EnterExitState.Visible) Color.Blue else Color.Gray
    }
    Box(
        modifier = Modifier
            .size(128.dp)
            .background(background)
    )
}

برای کسب اطلاعات بیشتر درباره استفاده از Transition برای مدیریت پویانمایی‌ها، به پویانمایی هم‌زمان چندین دارایی با یک گذار مراجعه کنید.

پویانمایی براساس وضعیت هدف

AnimatedContent ترکیب‌پذیر محتوای خود را هنگام تغییر براساس حالت هدف پویانمایی می‌کند.

Row {
    var count by remember { mutableIntStateOf(0) }
    Button(onClick = { count++ }) {
        Text("Add")
    }
    AnimatedContent(
        targetState = count,
        label = "animated content"
    ) { targetCount ->
        // Make sure to use `targetCount`, not `count`.
        Text(text = "Count: $targetCount")
    }
}

به‌طور پیش‌فرض، محتوای اولیه محو می‌شود و سپس محتوای هدف ظاهر می‌شود (این رفتار محو شدن نامیده می‌شود). با مشخص کردن ContentTransform شیء برای پارامتر transitionSpec می‌توانید این رفتار پویانمایی را سفارشی‌سازی کنید. با ترکیب کردن شیء EnterTransition با شیء ExitTransition بااستفاده از تابع میان‌وند with می‌توانید نمونه‌ای از ContentTransform ایجاد کنید. با پیوست کردن آن با تابع میان‌وندی SizeTransform می‌توانید آن را به شیء ContentTransform اعمال کنید. using.

AnimatedContent(
    targetState = count,
    transitionSpec = {
        // Compare the incoming number with the previous number.
        if (targetState > initialState) {
            // If the target number is larger, it slides up and fades in
            // while the initial (smaller) number slides up and fades out.
            slideInVertically { height -> height } + fadeIn() togetherWith
                slideOutVertically { height -> -height } + fadeOut()
        } else {
            // If the target number is smaller, it slides down and fades in
            // while the initial number slides down and fades out.
            slideInVertically { height -> -height } + fadeIn() togetherWith
                slideOutVertically { height -> height } + fadeOut()
        }.using(
            // Disable clipping since the faded slide-in/out should
            // be displayed out of bounds.
            SizeTransform(clip = false)
        )
    }, label = "animated content"
) { targetCount ->
    Text(text = "$targetCount")
}

EnterTransition مشخص می‌کند که محتوای هدف چگونه باید ظاهر شود، و ExitTransition مشخص می‌کند که محتوای اولیه چگونه باید ناپدید شود. علاوه‌بر همه عملکردهای EnterTransition و ExitTransition دردسترس برای AnimatedVisibility، AnimatedContent slideIntoContainer و slideOutOfContainer را ارائه می‌دهد. این‌ها جایگزین‌های مناسبی برای slideInHorizontally/Vertically و slideOutHorizontally/Vertically هستند که فاصله اسلاید را براساس اندازه‌های محتوای اولیه و محتوای هدف محتوای AnimatedContent محاسبه می‌کنند.

SizeTransform مشخص می‌کند اندازه چگونه بین محتوای اولیه و هدف پویانمایی شود. هنگام ایجاد پویانمایی، به هر دو اندازه اولیه و اندازه هدف دسترسی دارید. SizeTransform همچنین کنترل می‌کند که آیا محتوا باید درطول پویانمایی‌ها به اندازه عنصر برش داده شود یا نه.

var expanded by remember { mutableStateOf(false) }
Surface(
    color = MaterialTheme.colorScheme.primary,
    onClick = { expanded = !expanded }
) {
    AnimatedContent(
        targetState = expanded,
        transitionSpec = {
            fadeIn(animationSpec = tween(150, 150)) togetherWith
                fadeOut(animationSpec = tween(150)) using
                SizeTransform { initialSize, targetSize ->
                    if (targetState) {
                        keyframes {
                            // Expand horizontally first.
                            IntSize(targetSize.width, initialSize.height) at 150
                            durationMillis = 300
                        }
                    } else {
                        keyframes {
                            // Shrink vertically first.
                            IntSize(initialSize.width, targetSize.height) at 150
                            durationMillis = 300
                        }
                    }
                }
        }, label = "size transform"
    ) { targetExpanded ->
        if (targetExpanded) {
            Expanded()
        } else {
            ContentIcon()
        }
    }
}

پویانمایی کردن گذرهای ورود و خروج فرزند

دقیقاً مانند AnimatedVisibility، اصلاح‌کننده animateEnterExit درون لامبدای محتوای AnimatedContent دردسترس است. از این برای اعمال EnterAnimation و ExitAnimation روی هریک از فرزندان مستقیم یا غیرمستقیم به‌طور جداگانه استفاده کنید.

افزودن پویانمایی سفارشی

دقیقاً مثل AnimatedVisibility، فیلد transition در لامبدای محتوای AnimatedContent دردسترس است. از این برای ایجاد جلوه پویانمایی سفارشی استفاده کنید که به‌طور هم‌زمان با انتقال AnimatedContent اجرا می‌شود. برای جزئیات، به updateTransition مراجعه کنید.

پویانمایی بین دو چیدمان

Crossfade بین دو چیدمان با پویانمایی محو کردن متقاطع پویانمایی می‌کند. با تغییر مقدار ارسال‌شده به پارامتر current، محتوا با پویانمایی محو شدن متقاطع عوض می‌شود.

var currentPage by remember { mutableStateOf("A") }
Crossfade(targetState = currentPage, label = "cross fade") { screen ->
    when (screen) {
        "A" -> Text("Page A")
        "B" -> Text("Page B")
    }
}

اصلاح‌کننده‌های پویانمایی داخلی

‫Compose اصلاح‌کننده‌هایی برای پویانمایی تغییرات خاص مستقیماً در ترکیب‌پذیرها ارائه می‌دهد.

پویانمایی تغییرات اندازه عنصر ترکیبی

عنصر ترکیبی سبز که تغییر اندازه آن به‌آرامی متحرک می‌شود.
شکل ۲. عنصر ترکیبی که به‌نرمی بین اندازه کوچک و بزرگ‌تر پویانمایی می‌کند

توصیف‌گر 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
        }

) {
}

پویانمایی‌های مورد فهرست

اگر به‌دنبال پویانمایی کردن تغییر ترتیب موارد در فهرست یا جدول «تنبل» هستید، به مستندات پویانمایی مورد چیدمان تنبل نگاهی بیندازید.