تتضمّن 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 باستخدام عامل التشغيل +، ويقبل كل منها مَعلمات اختيارية لتخصيص سلوكه. يمكنك الاطّلاع على الصفحات المرجعية لمزيد من المعلومات.
أمثلة على انتقالات الدخول والخروج
يوفّر 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 الأساسي باستخدام السمة transition داخل تعبير lambda للمحتوى في 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. يمكنك إنشاء مثيل من ContentTransform من خلال دمج كائن EnterTransition مع كائن ExitTransition باستخدام الدالة الثنائية with. يمكنك تطبيق 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
داخل تعبير lambda للمحتوى في AnimatedContent. استخدِم هذا المعدِّل لتطبيق EnterAnimation وExitAnimation على كل من العناصر الثانوية المباشرة أو غير المباشرة بشكل منفصل.
إضافة صورة متحركة مخصّصة
تمامًا مثل AnimatedVisibility، يتوفّر الحقل transition داخل تعبير lambda للمحتوى في 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 } ) { }
صور متحركة لعناصر القائمة
اقتراحات مخصصة لك
- ملاحظة: يتم عرض نص الرابط عندما يكون JavaScript غير مفعّل
- الصور المتحركة المستندة إلى القيمة
- الصور المتحركة في Compose
- دعم أدوات الصور المتحركة {:#tooling}