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

Compose با ترکیب‌کننده‌ها و اصلاح‌کننده‌های داخلی برای مدیریت موارد استفاده متداول از انیمیشن ارائه می‌شود.

ساخته شده در متحرک composable

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

رنگ سبز خود را نشان می دهد و پنهان می کند
شکل 1. متحرک سازی ظاهر و ناپدید شدن یک آیتم در یک ستون

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

مثال های EnterTransition و ExitTransition

EnterTransition خروج از انتقال
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 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 در داخل محتوا لامبدا برای 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 به updateTransition مراجعه کنید.

متحرک سازی بر اساس حالت هدف با AnimatedContent

قابلیت Composable 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")
    }
}

توجه داشته باشید که همیشه باید از پارامتر لامبدا استفاده کنید و آن را به محتوا منعکس کنید. API از این مقدار به عنوان کلید برای شناسایی محتوایی که در حال حاضر نشان داده شده است استفاده می کند.

به طور پیش فرض، محتوای اولیه محو می شود و سپس محتوای مورد نظر محو می شود (به این رفتار، محو شدن از طریق ) می گویند. شما می توانید این رفتار انیمیشن را با تعیین یک شی ContentTransform به پارامتر transitionSpec شخصی سازی کنید. می توانید ContentTransform با ترکیب EnterTransition با ExitTransition با استفاده از تابع with infix ایجاد کنید. می‌توانید SizeTransform با پیوست کردن آن با تابع using به 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 در داخل محتوای لامبدا AnimatedContent موجود است. از این برای اعمال EnterAnimation و ExitAnimation برای هر یک از کودکان مستقیم یا غیر مستقیم به طور جداگانه استفاده کنید.

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

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

با Crossfade بین دو طرح بندی متحرک شوید

Crossfade بین دو طرح بندی با انیمیشن 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")
    }
}

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

تغییر اندازه قابل ترکیب با animateContentSize

متحرک سازی رنگ سبز، اندازه آن به آرامی تغییر می کند.
شکل 2. متحرک سازی هموار بین اندازه کوچک و بزرگتر

اصلاح کننده 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 هستید، نگاهی به مستندات انیمیشن مورد طرح بندی تنبل بیندازید.

{% کلمه به کلمه %} {% آخر کلمه %} {% کلمه به کلمه %} {% آخر کلمه %}