تتضمّن Compose عناصر قابلة للإنشاء ومعدِّلات مدمجة للتعامل مع حالات الاستخدام الشائعة للرسوم المتحركة.
عناصر قابلة للإنشاء متحركة مضمّنة
إضافة الحركة إلى ظهور العناصر واختفائها باستخدام AnimatedVisibility

تعمل الدالة البرمجية القابلة للإنشاء
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
يوفّر 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) ) }
راجِع updateTransition لمعرفة تفاصيل حول Transition
.
تحريك العناصر استنادًا إلى الحالة المستهدَفة باستخدام AnimatedContent
تعمل الدالة البرمجية القابلة للإنشاء 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") } }
يُرجى العِلم أنّه يجب دائمًا استخدام مَعلمة lambda وعكسها في المحتوى. تستخدم واجهة برمجة التطبيقات هذه القيمة كمفتاح لتحديد المحتوى المعروض حاليًا.
يتم تلقائيًا إخفاء المحتوى الأوّلي تدريجيًا ثم إظهار المحتوى المستهدف تدريجيًا (يُطلق على هذا السلوك اسم التلاشي التدريجي). يمكنك تخصيص سلوك هذه الحركة من خلال تحديد عنصر 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
تعرض 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

يُنشئ المعدِّل 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 item animation.
أفلام مُقترَحة لك
- ملاحظة: يتم عرض نص الرابط عندما تكون JavaScript غير مفعّلة
- الصور المتحركة المستندة إلى القيمة
- الصور المتحركة في Compose
- دعم أدوات الصور المتحركة {:#tooling}