הרכיב SwipeToDismissBox מאפשר למשתמש לסגור או לעדכן פריט על ידי החלקה ימינה או שמאלה.
ממשק API
אפשר להשתמש ב-composable SwipeToDismissBox כדי להטמיע פעולות שמופעלות על ידי תנועות החלקה. בין הפרמטרים העיקריים:
state: המצבSwipeToDismissBoxStateנוצר כדי לאחסן את הערך שנוצר על ידי חישובים בפריט ההחלקה, שמפעיל אירועים כשהוא נוצר.backgroundContent: רכיב קומפוזיציה שניתן להתאמה אישית, שמוצג מאחורי תוכן הפריט ונחשף כשמחליקים על התוכן.
דוגמה בסיסית: עדכון או סגירה באמצעות החלקה
בקטעי הקוד שבדוגמאות האלה מוצגת הטמעה של החלקה שמעדכנת את הפריט כשמחליקים מתחילתו ועד סופו, או סוגרת את הפריט כשמחליקים מסופו עד לתחילתו.
data class TodoItem( val itemDescription: String, var isItemDone: Boolean = false )
@Composable fun TodoListItem( todoItem: TodoItem, onToggleDone: (TodoItem) -> Unit, onRemove: (TodoItem) -> Unit, modifier: Modifier = Modifier, ) { val swipeToDismissBoxState = rememberSwipeToDismissBoxState( confirmValueChange = { if (it == StartToEnd) onToggleDone(todoItem) else if (it == EndToStart) onRemove(todoItem) // Reset item when toggling done status it != StartToEnd } ) SwipeToDismissBox( state = swipeToDismissBoxState, modifier = modifier.fillMaxSize(), backgroundContent = { when (swipeToDismissBoxState.dismissDirection) { StartToEnd -> { Icon( if (todoItem.isItemDone) Icons.Default.CheckBox else Icons.Default.CheckBoxOutlineBlank, contentDescription = if (todoItem.isItemDone) "Done" else "Not done", modifier = Modifier .fillMaxSize() .background(Color.Blue) .wrapContentSize(Alignment.CenterStart) .padding(12.dp), tint = Color.White ) } EndToStart -> { Icon( imageVector = Icons.Default.Delete, contentDescription = "Remove item", modifier = Modifier .fillMaxSize() .background(Color.Red) .wrapContentSize(Alignment.CenterEnd) .padding(12.dp), tint = Color.White ) } Settled -> {} } } ) { ListItem( headlineContent = { Text(todoItem.itemDescription) }, supportingContent = { Text("swipe me to update or remove.") } ) } }
נקודות עיקריות לגבי הקוד
swipeToDismissBoxStateמנהל את מצב הרכיב. הוא מפעיל את פונקציית ה-callbackconfirmValueChangeבסיום האינטראקציה עם הפריט. גוף הקריאה החוזרת מטפל בפעולות השונות האפשריות. הפונקציה הזו מחזירה ערך בוליאני שמציין אם צריך להציג אנימציה לסגירה. במקרה כזה:- אם מחליקים את הפריט מההתחלה לסוף, מתבצעת קריאה ל-lambda של 
onToggleDone, עם העברת הערך הנוכחי שלtodoItem. זה תואם לעדכון של פריט המשימות. - אם מחליקים את הפריט מהסוף להתחלה, מתבצעת קריאה ל-lambda של 
onRemove, עם העברת הערך הנוכחי שלtodoItem. הפעולה הזו תואמת למחיקה של פריט ברשימת המשימות. it != StartToEnd: השורה הזו מחזירה את הערךtrueאם כיוון החלקה הוא לאStartToEnd, ואת הערךfalseבמקרים אחרים. החזרתfalseמונעת את היעלמות ה-SwipeToDismissBoxבאופן מיידי אחרי החלקה של 'הפעלה/השבתה', ומאפשרת להציג אישור חזותי או אנימציה.
- אם מחליקים את הפריט מההתחלה לסוף, מתבצעת קריאה ל-lambda של 
 SwipeToDismissBoxמאפשרת אינטראקציות של החלקה אופקית בכל פריט. במצב רגילה מוצג התוכן הפנימי של הרכיב, אבל כשהמשתמש מתחיל להחליק, התוכן מוסר ומוצגbackgroundContent. גם התוכן הרגיל וגם ה-backgroundContentמקבלים את האילוצים המלאים של מאגר ההורה כדי להציג את עצמם. ה-contentמצויר מעל ה-backgroundContent. במקרה כזה:backgroundContentמיושם כ-Iconעם צבע רקע שמבוסס עלSwipeToDismissBoxValue:BlueכשמחליקיםStartToEnd– החלפת מצב של פריט ברשימת המשימות.RedכשמחליקיםEndToStart– מחיקת פריט ברשימת המשימות.- לא מוצגת תמונה ברקע של 
Settled– כשלא מחליקים על הפריט, לא מוצגת תמונה ברקע. - באופן דומה, הסמל 
Iconשמוצג משתנה בהתאם לכיוון ההחלקה: StartToEndמוצג סמלCheckBoxכשהמשימה בוצעה וסמלCheckBoxOutlineBlankכשהיא לא בוצעה.EndToStartמוצג סמלDelete.
@Composable private fun SwipeItemExample() { val todoItems = remember { mutableStateListOf( TodoItem("Pay bills"), TodoItem("Buy groceries"), TodoItem("Go to gym"), TodoItem("Get dinner") ) } LazyColumn { items( items = todoItems, key = { it.itemDescription } ) { todoItem -> TodoListItem( todoItem = todoItem, onToggleDone = { todoItem -> todoItem.isItemDone = !todoItem.isItemDone }, onRemove = { todoItem -> todoItems -= todoItem }, modifier = Modifier.animateItem() ) } } }
נקודות עיקריות לגבי הקוד
mutableStateListOf(...)יוצר רשימה שניתן לצפות בה, שיכולה להכיל אובייקטים מסוגTodoItem. כשמוסיפים או מסירים פריט מהרשימה הזו, Compose מרכיב מחדש את החלקים בממשק המשתמש שתלויים בו.- בתוך 
mutableStateListOf(), מתבצעת אתחול של ארבעה אובייקטים מסוגTodoItemעם התיאורים המתאימים: 'תשלום חשבונות', 'קניית מצרכים', 'ביקור בחדר כושר' ו'ארוחת ערב'. 
- בתוך 
 LazyColumnמציג רשימה שלtodoItemsבגלילה אנכית.onToggleDone = { todoItem -> ... }היא פונקציית קריאה חוזרת (callback) שמופיעה ב-TodoListItemכשהמשתמש מסמנים אובייקט כ'הושלם'. הוא מעדכן את המאפייןisItemDoneשלtodoItem. מכיוון ש-todoItemsהואmutableStateListOf, השינוי הזה מפעיל יצירת קומפוזיציה מחדש ומעדכן את ממשק המשתמש.onRemove = { todoItem -> ... }היא פונקציית קריאה חוזרת שמופעלת כשהמשתמש מסיר את הפריט. הפונקציה מסירה את הערך הספציפי שלtodoItemמהרשימהtodoItems. הפעולה הזו גם גורמת ליצירת קומפוזיציה מחדש, והפריט יוסר מהרשימה המוצגת.- המערכת מחילה את המשתנה 
animateItemעל כלTodoListItem, כך ש-placementSpecשל המשתנה ייכלל כשהפריט ייסגר. כך תוכלו לראות את ההסרה של הפריט ואת הסדר מחדש של שאר הפריטים ברשימה. 
התוצאה
בסרטון הבא מוצגת הפונקציונליות הבסיסית של החלקה כדי לסגור מהקטעים הקודמים:
הקוד המלא לדוגמה זמין בקובץ המקור ב-GitHub.
דוגמה מתקדמת: אנימציה של צבע הרקע בזמן החלקה
בקטעים הבאים מוסבר איך לשלב ערך סף מיקומי כדי ליצור אנימציה של צבע הרקע של פריט בזמן החלקה.
data class TodoItem( val itemDescription: String, var isItemDone: Boolean = false )
@Composable fun TodoListItemWithAnimation( todoItem: TodoItem, onToggleDone: (TodoItem) -> Unit, onRemove: (TodoItem) -> Unit, modifier: Modifier = Modifier, ) { val swipeToDismissBoxState = rememberSwipeToDismissBoxState( confirmValueChange = { if (it == StartToEnd) onToggleDone(todoItem) else if (it == EndToStart) onRemove(todoItem) // Reset item when toggling done status it != StartToEnd } ) SwipeToDismissBox( state = swipeToDismissBoxState, modifier = modifier.fillMaxSize(), backgroundContent = { when (swipeToDismissBoxState.dismissDirection) { StartToEnd -> { Icon( if (todoItem.isItemDone) Icons.Default.CheckBox else Icons.Default.CheckBoxOutlineBlank, contentDescription = if (todoItem.isItemDone) "Done" else "Not done", modifier = Modifier .fillMaxSize() .drawBehind { drawRect(lerp(Color.LightGray, Color.Blue, swipeToDismissBoxState.progress)) } .wrapContentSize(Alignment.CenterStart) .padding(12.dp), tint = Color.White ) } EndToStart -> { Icon( imageVector = Icons.Default.Delete, contentDescription = "Remove item", modifier = Modifier .fillMaxSize() .background(lerp(Color.LightGray, Color.Red, swipeToDismissBoxState.progress)) .wrapContentSize(Alignment.CenterEnd) .padding(12.dp), tint = Color.White ) } Settled -> {} } } ) { OutlinedCard(shape = RectangleShape) { ListItem( headlineContent = { Text(todoItem.itemDescription) }, supportingContent = { Text("swipe me to update or remove.") } ) } } }
נקודות עיקריות לגבי הקוד
drawBehindמצייר ישירות על לוח הציור מאחורי התוכן של ה-composable שלIcon.drawRect()מצייר מלבן על הלוח וממלא את כל גבולות היקף הציור ב-Colorשצוין.
- כשמחליקים, צבע הרקע של הפריט עובר מעבר חלק באמצעות 
lerp.- כשמחליקים מ-
StartToEnd, צבע הרקע משתנה בהדרגה מאפור בהיר לכחול. - כשמחליקים מ-
EndToStart, צבע הרקע משתנה בהדרגה מאפור בהיר לאדום. - עוצמת המעבר מצבע אחד לצבע הבא נקבעת לפי 
swipeToDismissBoxState.progress. 
 - כשמחליקים מ-
 OutlinedCardמוסיף הפרדה חזותית עדינה בין הפריטים ברשימה.
@Composable private fun SwipeItemWithAnimationExample() { val todoItems = remember { mutableStateListOf( TodoItem("Pay bills"), TodoItem("Buy groceries"), TodoItem("Go to gym"), TodoItem("Get dinner") ) } LazyColumn { items( items = todoItems, key = { it.itemDescription } ) { todoItem -> TodoListItemWithAnimation( todoItem = todoItem, onToggleDone = { todoItem -> todoItem.isItemDone = !todoItem.isItemDone }, onRemove = { todoItem -> todoItems -= todoItem }, modifier = Modifier.animateItem() ) } } }
נקודות עיקריות לגבי הקוד
- נקודות מפתח לגבי הקוד הזה מפורטות בקטע נקודות מפתח מהקטע הקודם, שבו מתואר קטע קוד זהה.
 
התוצאה
בסרטון הבא מוצגת הפונקציונליות המתקדמת עם צבע רקע מונפש:
הקוד המלא לדוגמה זמין בקובץ המקור ב-GitHub.