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

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

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

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

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

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

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

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

פלטפורמת ה-API

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

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

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

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

בקטע הקוד הבא מופיעה דוגמה מפורטת יחסית. כשהמשתמש לוחץ על הכפתור, האפליקציה מציגה את אינדיקטור ההתקדמות ומפעילה קורוטינה שמגדילה בהדרגה את הערך של 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.

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