אינדיקטורים של התקדמות

אינדיקטורים של התקדמות מציגים באופן חזותי את הסטטוס של פעולה. הם משתמשים בתנועה כדי להראות למשתמשים כמה קרוב התהליך לסיום, כמו טעינה או עיבוד של נתונים. הם יכולים גם לציין שמתבצע עיבוד, בלי להתייחס למידת הקרבה לסיום.

ריכזנו כאן שלושה תרחישים לדוגמה שכדאי להשתמש בהם במחוון התקדמות:

  • טעינת תוכן: בזמן אחזור תוכן מרשת, כמו טעינת תמונה או נתונים של פרופיל משתמש.
  • העלאת קבצים: תנו למשתמשים משוב על משך הזמן שההעלאה עשויה להימשך.
  • עיבוד ארוך: כשהאפליקציה מעבדת כמות גדולה של נתונים, כדאי להראות למשתמש כמה מהם כבר עובדו.

ב-Material Design יש שני סוגים של אינדיקטורים להתקדמות:

  • מוגדר: מציג בדיוק את מידת ההתקדמות.
  • לא מוגדר: אנימציה שפועלת ברצף בלי קשר להתקדמות.

באופן דומה, אינדיקטור התקדמות יכול להופיע באחת משתי הצורות הבאות:

  • ליניארי: סרגל אופקי שמתמלא משמאל לימין.
  • מעגלי: עיגול שהקו שלו מתארך עד שהוא מקיף את כל העיגול.
אינדיקטור התקדמות לינארי לצד אינדיקטור התקדמות מעגלי.
תרשים 1. שני הסוגים של אינדיקטורים להתקדמות.

פלטפורמת ה-API

אפשר להשתמש בכמה רכיבים קומפוזביליים כדי ליצור אינדיקטורים של התקדמות שתואמים לעיצוב Material Design, אבל הפרמטרים שלהם לא שונים בהרבה. הנה כמה מהפרמטרים החשובים שכדאי לזכור:

  • ‫progress: ההתקדמות הנוכחית שמוצגת באינדיקטור. צריך להעביר Float בין 0.0 ל-1.0.
  • ‫color: הצבע של האינדיקטור בפועל. כלומר, החלק ברכיב שמשקף את ההתקדמות ומקיף את הרכיב כולו כשההתקדמות הושלמה.
  • ‫trackColor: הצבע של הפס שעליו מצויר האינדיקטור.

אינדיקטורים מוגדרים

אינדיקטור מוגדר משקף בדיוק את מידת ההשלמה של פעולה. משתמשים ברכיבים הניתנים לקישור LinearProgressIndicator או CircularProgressIndicator ומעבירים ערך לפרמטר progress.

הקטע הבא מספק דוגמה מפורטת יחסית. כשהמשתמש לוחץ על הכפתור, האפליקציה מציגה את אינדיקטור ההתקדמות ומפעילה פונקציית coroutine שמגדילה בהדרגה את הערך של progress. כתוצאה מכך, אינדיקטור ההתקדמות עולה בהתאם.

@Composable
fun LinearDeterminateIndicator() {
    var currentProgress by remember { mutableFloatStateOf(0f) }
    var loading by remember { mutableStateOf(false) }
    val scope = rememberCoroutineScope() // Create a coroutine scope

    Column(
        verticalArrangement = Arrangement.spacedBy(12.dp),
        horizontalAlignment = Alignment.CenterHorizontally,
        modifier = Modifier.fillMaxWidth()
    ) {
        Button(onClick = {
            loading = true
            scope.launch {
                loadProgress { progress ->
                    currentProgress = progress
                }
                loading = false // Reset loading when the coroutine finishes
            }
        }, enabled = !loading) {
            Text("Start loading")
        }

        if (loading) {
            LinearProgressIndicator(
                progress = { currentProgress },
                modifier = Modifier.fillMaxWidth(),
            )
        }
    }
}

/** Iterate the progress value */
suspend fun loadProgress(updateProgress: (Float) -> Unit) {
    for (i in 1..100) {
        updateProgress(i.toFloat() / 100)
        delay(100)
    }
}

כשהטעינה הושלמה באופן חלקי, האינדיקטור הליניארי בדוגמה הקודמת נראה כך:

באופן דומה, האינדיקטור המעגלי מופיע כך:

אינדיקטורים לא מוגדרים

אינדיקטור לא מוגדר לא משקף את מידת ההתקדמות של הפעולה, אלא משתמש בתנועה כדי לציין למשתמש שהעיבוד נמשך, בלי לציין את מידת ההתקדמות.

כדי ליצור אינדיקטור התקדמות לא מוגדר, משתמשים בפונקציה הקומפוזבילית LinearProgressIndicator או CircularProgressIndicator, אבל לא מעבירים ערך ל-progress. בדוגמה הבאה אפשר לראות איך להחליף מצב של אינדיקטור לא מוגדר בלחיצה על כפתור.

@Composable
fun IndeterminateCircularIndicator() {
    var loading by remember { mutableStateOf(false) }

    Button(onClick = { loading = true }, enabled = !loading) {
        Text("Start loading")
    }

    if (!loading) return

    CircularProgressIndicator(
        modifier = Modifier.width(64.dp),
        color = MaterialTheme.colorScheme.secondary,
        trackColor = MaterialTheme.colorScheme.surfaceVariant,
    )
}

הדוגמה הבאה ממחישה את ההטמעה הזו כשהאינדיקטור פעיל:

הדוגמה הבאה היא של אותה הטמעה, אבל עם LinearProgressIndicator במקום CircularProgressIndicator.

מקורות מידע נוספים