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