Swipeable הוא ממשק API של Compose Material שעוזר ליצור רכיבים שאפשר להחליק ביניהם בין מצבים נפרדים, כמו גיליונות תחתונים, תיבות אחסון או החלקה כדי לסגור. כדי לתמוך טוב יותר בתרחישי שימוש מתקדמים, כמו עוגנים שמסתמכים על גודל הרכיב, פרסמנו את AnchoredDraggable – רכיב חלופי ב-Compose-Foundation 1.6.0-alpha01. AnchoredDraggable הוא ממשק API בסיסי ליצירת רכיבים שניתן לגרור עם מצבים מוצמדים, כמו גיליונות תחתונים, תיבות אחסון או החלקה כדי לסגור.
ממשקי ה-API של Swipeable ב-Material הוצאו משימוש לטובת AnchoredDraggable ב-Foundation, והם יוסרו במהדורה עתידית. במדריך הזה מוסבר איך לעבור ממשקי API של Swipeable ל-AnchoredDraggable.
העברה של SwipeableState אל AnchoredDraggableState
קודם כול, צריך לזהות שינויים בבעלים של המצב. לא ניתן להעביר בירושה את AnchoredDraggableState, וההיסט מיוצג כ-Float.NaN לפני אתחול.
עדכון של בעל הסטטוס
AnchoredDraggableState היא כיתה סופית, כלומר אי אפשר לרשת ממנה. אם הרכיב הקיים עובר בירושה מ-SwipeableState, מעדכנים את הבעלים של המצב כך שיכיל הפניה ל-AnchoredDraggableState במקום לעבור בירושה ממנו:
עם פונקציית החלקה
class MySwitchState: SwipeableState()
AnchoredDraggable
class MySwitchState {
private val anchoredDraggableState = AnchoredDraggableState(...)
}
מכיוון שבעלים המצב כבר לא יורש מ-SwipeableState, יכול להיות שתצטרכו לחשוף את ממשקי ה-API בעצמכם. ממשקי ה-API הנפוצים ביותר שבהם אפשר להשתמש הם offset, progress, currentValue ו-targetValue.
גישה להיסט
בניגוד ל-Swipeable, הערך של offset ב-AnchoredDraggableState הוא Float.NaN לפני שהוא מופעל. ב-AnchoredDraggable, אפשר להעביר את הוויתורים ל-constructor של AnchoredDraggableState או לעדכן אותם דרך AnchoredDraggableState#updateAnchors. העברת העוגנים ל-constructor של AnchoredDraggableState מאתחלת את ההיסט באופן מיידי.
אם הווידג'טים של העוגנים תלויים בפריסה או עשויים להשתנות, כדאי להשתמש ב-AnchoredDraggableState#updateAnchors כדי למנוע יצירה מחדש של המצב כשהווידג'טים של העוגנים משתנים.
אם משתמשים ב-updateAnchors, ההיסט יהיה Float.NaN לפני העברת הוויתורים ל-updateAnchors. כדי להימנע ממצב שבו הערך Float.NaN מועבר בטעות לרכיבים, צריך להשתמש ב-AnchoredDraggableState#requireOffset כדי לדרוש שההיסט יופעל בזמן הקריאה. כך תוכלו לזהות חוסר עקביות או באגים אפשריים בשלב מוקדם.
@Composable
fun AnchoredDraggableBox() {
val state = remember { AnchoredDraggableState(...) }
val density = LocalDensity.current
val anchors = remember { DraggableAnchors { ... } }
SideEffect {
state.updateAnchors(anchors)
}
Box(
Modifier.offset { IntOffset(x = state.requireOffset(), y = 0) }
}
}
העברה של Modifier.swipeable אל Modifier.anchoredDraggable
Modifier.anchoredDraggable() מחליף את Modifier.swipeable. חלק מהפרמטרים של Modifier.swipeable() הועברו ישירות אל AnchoredDraggableState, כפי שמתואר בקטעים הבאים.
הגדרת עוגנים
מגדירים את הווידג'טים באמצעות שיטת ה-builder DraggableAnchors. לאחר מכן מעבירים אותם ל-constructor של AnchoredDraggableState#updateAnchors או של AnchoredDraggableState:
Constructor
enum class DragValue { Start, Center, End }
@Composable
fun AnchoredDraggableBox() {
val anchors = DraggableAnchors {
Start at -100.dp.toPx()
Center at 0f
End at 100.dp.toPx()
}
val state = remember {
AnchoredDraggableState(anchors = anchors)
}
Box(
Modifier.offset { IntOffset(x = state.requireOffset(), y = 0) }
)
}
updateAnchors
enum class DragValue { Start, Center, End }
@Composable
fun AnchoredDraggableBox() {
val state = remember { AnchoredDraggableState(...) }
val density = LocalDensity.current
val anchors = with (density) {
DraggableAnchors {
Start at -100.dp.toPx()
Center at 0f
End at 100.dp.toPx()
}
}
SideEffect {
state.updateAnchors(anchors)
}
Box(
Modifier.offset { IntOffset(x = state.requireOffset(), y = 0) }
)
}
אם ה-anchors סטטיים, מעבירים אותם למבנה ה-constructor. אם הם תלויים בפריסה או שהם לא סטטיים, כדאי להשתמש ב-updateAnchors.
הגדרת ערכי סף לפי מיקום
הסוג והשם של הפרמטר thresholds השתנו. במקום ממשק ThresholdConfig נפרד, ל-AnchoredDraggableState יש פרמטר positionalThreshold שמקבל פונקציית למדה שמחזירה את המיקום של הסף. לדוגמה, סף מיקום של 50% יכול לבטא כך:
val anchoredDraggableState = AnchoredDraggableState(
positionalThreshold = { distance -> distance * 0.5f },
...
)
ערך סף מיקומי של 56dp יכול להתבטא באופן הבא:
val density = LocalDensity.current
val anchoredDraggableState = AnchoredDraggableState(
positionalThreshold = { with(density) { 56.dp.toPx() } },
...
)
הגדרת ערכי סף למהירות
ערכי הסף של המהירות מועברים גם למבנה ה-constructor של AnchoredDraggableState, וגם הם באים לידי ביטוי כפונקציית lambda:
val density = LocalDensity.current
val anchoredDraggableState = AnchoredDraggableState(
velocityThreshold = { with(density) { 125.dp.toPx() } },
...
)
שינויים בממשק ה-API
בהמשך תוכלו למצוא סקירה כללית של השינויים בפלטפורמת ה-API.
AnchoredDraggableState
|
|
|---|---|
|
|
|
|
|
|
|
|
|
|
|
לא רלוונטי |
|
|
|
|
|
|
|
|
|
|
|
Modifier.anchoredDraggable
|
|
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
מועבר ל-constructor של |
|
החשבון עדיין לא נתמך. אפשר לראות את הסטטוס העדכני ביותר בכתובת b/288084801. |
|
מועברים למבנה ה-constructor של |