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

Compose با composableها و modifierهای داخلی برای مدیریت موارد استفاده رایج از انیمیشن ارائه می‌شود.

ساخته شده در ترکیب‌های متحرک

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

ظاهر و ناپدید شدن را متحرک کنید

سبزِ ترکیب‌پذیر، خود را نشان می‌دهد و پنهان می‌کند
شکل ۱. متحرک‌سازی ظاهر و ناپدید شدن یک آیتم در یک ستون.

کامپوننت 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 را با یک عملگر + ترکیب کنید و هر کدام پارامترهای اختیاری را برای سفارشی‌سازی رفتار خود می‌پذیرند. برای اطلاعات بیشتر به صفحات مرجع مراجعه کنید.

مثال‌های انتقال ورود و خروج

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

AnimatedVisibility همچنین نوعی ارائه می‌دهد که آرگومان MutableTransitionState را دریافت می‌کند. این به شما امکان می‌دهد به محض اضافه شدن AnimatedVisibility composable به درخت ترکیب، یک انیمیشن را فعال کنید. همچنین برای مشاهده وضعیت انیمیشن مفید است.

// 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 composable و انیمیشن‌های ورود و خروج خود فرزند است.

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 composable مشخص کنید.

اضافه کردن انیمیشن سفارشی

اگر می‌خواهید جلوه‌های انیمیشن سفارشی را فراتر از انیمیشن‌های ورود و خروج داخلی اضافه کنید، با استفاده از ویژگی transition درون المبدای content برای AnimatedVisibility به نمونه Transition زیرین دسترسی پیدا کنید. هر حالت انیمیشنی که به نمونه Transition اضافه شود، همزمان با انیمیشن‌های ورود و خروج AnimatedVisibility اجرا خواهد شد. AnimatedVisibility قبل از حذف محتوای آن، منتظر می‌ماند تا تمام انیمیشن‌های موجود در Transition تمام شوند. برای انیمیشن‌های خروج که مستقل از Transition ایجاد شده‌اند (مانند استفاده از animate*AsStateAnimatedVisibility نمی‌تواند آنها را در نظر بگیرد و بنابراین ممکن است محتوای قابل ترکیب را قبل از اتمام آنها حذف کند.

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 برای مدیریت انیمیشن‌ها، به بخش «متحرک‌سازی چندین ویژگی به طور همزمان با یک 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 infix، یک نمونه از ContentTransform ایجاد کنید. می‌توانید SizeTransform با اتصال آن با تابع using infix به شیء ContentTransform اعمال کنید.

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 درون المبدای content از AnimatedContent موجود است. از این برای اعمال EnterAnimation و ExitAnimation به هر یک از فرزندان مستقیم یا غیرمستقیم به طور جداگانه استفاده کنید.

اضافه کردن انیمیشن سفارشی

درست مانند AnimatedVisibility ، فیلد transition درون المبدای content از AnimatedContent موجود است. از این برای ایجاد یک جلوه انیمیشن سفارشی که همزمان با transition AnimatedContent اجرا می‌شود، استفاده کنید. برای جزئیات بیشتر به updateTransition مراجعه کنید.

متحرک‌سازی بین دو طرح‌بندی

Crossfade با استفاده از انیمیشن crossfade بین دو طرح‌بندی جابه‌جا می‌شود. با تغییر مقدار ارسالی به پارامتر current ، محتوا با یک انیمیشن crossfade جابه‌جا می‌شود.

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

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

Compose اصلاح‌کننده‌هایی را برای متحرک‌سازی تغییرات خاص مستقیماً روی composableها فراهم می‌کند.

متحرک‌سازی تغییرات اندازه قابل ترکیب

سبزِ قابل ترکیب که به طور انیمیشنی تغییر اندازه می‌دهد، روان است.
شکل ۲. انیمیشن روان و قابل ترکیب بین اندازه کوچک و بزرگتر

اصلاح‌کننده‌ی 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
        }

) {
}

انیمیشن‌های آیتم‌های لیست

اگر به دنبال متحرک‌سازی ترتیب‌بندی مجدد آیتم‌ها در یک لیست یا شبکه Lazy هستید، به مستندات انیمیشن آیتم Lazy layout نگاهی بیندازید.

{% کلمه به کلمه %} {% فعل کمکی %} {% کلمه به کلمه %} {% فعل کمکی %}