ביצוע פעולות במקלדת

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

מקשי הקיצור שמוגדרים כברירת מחדל

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

מקש קיצור פעולה רכיבי Composable שתומכים בקיצור הדרך
‫Shift+Ctrl+חץ שמאלה/חץ ימינה בחירת הטקסט עד תחילת/סוף המילה BasicTextField, TextField
‫Shift+Ctrl+חץ למעלה/חץ למטה בחירת הטקסט עד לתחילת או לסוף הפסקה BasicTextField, TextField
‫Shift+Alt+חץ למעלה/חץ למטה או Shift+Meta+חץ שמאלה/חץ ימינה בחירת הטקסט עד תחילת או סוף הטקסט BasicTextField, TextField
‫Shift+חץ שמאלה/חץ ימינה בחירת דמויות BasicTextField, TextField
Ctrl+A בחירת הכול BasicTextField, TextField
Ctrl+C/Ctrl+X/Ctrl+V העתקה/גזירה/הדבקה BasicTextField, TextField
Ctrl+Z/Ctrl+Shift+Z ביטול פעולה או ביצוע מחדש BasicTextField, TextField
PageDown/PageUp גלילה ‫LazyColumn, מקש הצירוף verticalScroll, מקש הצירוף scrollable

אירועים מרכזיים

במצב כתיבה, אפשר לטפל בהקשה בודדת באמצעות מקש הצירוף onKeyEvent. המשנה מקבל ביטוי למדא שמופעל כשהרכיב שמשנים מקבל אירוע מקש. אירוע מרכזי מתואר כאובייקט KeyEvent. כדי לקבל את המידע על כל אירוע מרכזי, אפשר להפנות לאובייקט ב-lambda שמועבר ל-modifier‏ onKeyEvent.

הקשה על מקש שולחת שני אירועי מקשים. אחד מופעל כשהמשתמש לוחץ על המקש, והשני מופעל כשהמקש משוחרר. כדי להבחין בין שני האירועים המרכזיים, אפשר להפנות למאפיין type של האובייקט KeyEvent.

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

בקטע הקוד הבא אפשר לראות איך להפעיל פונקציה של doSomething() כשהמשתמש משחרר את המקש S ברכיב Box:

Box(
    modifier = Modifier
        .onKeyEvent {
            if (
                it.type == KeyEventType.KeyUp &&
                it.key == Key.S
            ) {
                doSomething()
                true
            } else {
                false
            }
        }
        .focusable()
) {
    Text("Press S key")
}

מקשי צירוף

לאובייקט KeyEvent יש את המאפיינים הבאים שמציינים אם מקשי הצירוף נלחצים או לא:

חשוב לתאר באופן ספציפי את האירועים המרכזיים שהאפליקציה מטפלת בהם. קטע הקוד הבא קורא לפונקציה doSomething() רק אם המשתמש משחרר את המקש S. אם המשתמש לוחץ על מקש צירוף כלשהו, כמו Shift, האפליקציה לא קוראת לפונקציה.

Box(
    modifier = Modifier
        .focusable()
        .onKeyEvent {
            if (
                it.type == KeyEventType.KeyUp &&
                it.key == Key.S &&
                !it.isAltPressed &&
                !it.isCtrlPressed &&
                !it.isMetaPressed &&
                !it.isShiftPressed
            ) {
                doSomething()
                true
            } else {
                false
            }
        }
) {
    Text("Press S key with a modifier key")
}

אירועים מסוג קליק על מקש הרווח ועל מקש Enter

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

MediaPlayer(modifier = Modifier.clickable { togglePausePlay() })

המשתנה clickable מיירט אירועי מקשים וקורא לפונקציית ה-callback‏ onClick() כשלוחצים על מקש הרווח או על Enter. לכן הפונקציה togglePausePlay() מופעלת כשלוחצים על מקש הרווח או על Enter בקטע הקוד.

אירועים מרכזיים שלא נעשה בהם שימוש

אירועים מרכזיים שלא נצרכו מועברים מהרכיב שבו האירוע התרחש לרכיב החיצוני שמקיף אותו. בדוגמה הבאה, ה-InnerComponent צורך אירועי מקשים כשמשחררים את המקש S, ולכן ה-OuterComponent לא מקבל אירועי מקשים שמופעלים על ידי שחרור המקש S. לכן הפונקציה actionB() אף פעם לא מופעלת.

אירועים מרכזיים אחרים ב-InnerComponent, כמו שחרור המקש D, יכולים להיות מטופלים על ידי OuterComponent. הפונקציה actionC() נקראת כי האירוע המרכזי של שחרור המקש D מופץ אל OuterComponent.

OuterComponent(
    modifier = Modifier.onKeyEvent {
        when {
            it.type == KeyEventType.KeyUp && it.key == Key.S -> {
                actionB() // This function is never called.
                true
            }

            it.type == KeyEventType.KeyUp && it.key == Key.D -> {
                actionC()
                true
            }

            else -> false
        }
    }
) {
    InnerComponent(
        modifier = Modifier.onKeyEvent {
            if (it.type == KeyEventType.KeyUp && it.key == Key.S) {
                actionA()
                true
            } else {
                false
            }
        }
    )
}

onKeyPreviewEvent modifier

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

val focusManager = LocalFocusManager.current
var textFieldValue by remember { mutableStateOf(TextFieldValue()) }

TextField(
    textFieldValue,
    onValueChange = {
        textFieldValue = it
    },
    modifier = Modifier.onPreviewKeyEvent {
        if (it.type == KeyEventType.KeyUp && it.key == Key.Tab) {
            focusManager.moveFocus(FocusDirection.Next)
            true
        } else {
            false
        }
    }
)

כברירת מחדל, הרכיב TextField מוסיף תו טאב בכל פעם שהמשתמשים לוחצים על המקש Tab, גם אם האירוע של המקש מטופל באמצעות מקש הצירוף onKeyEvent. כדי להזיז את מיקוד המקלדת בלי להוסיף תווי טאב, צריך לטפל באירוע המקלדת לפני שמפעילים את הפעולות שמשויכות לאירוע המקלדת, כמו בקטע הקוד. פונקציית ה-lambda‏ onKeyPreviewEvent() מיירטת את האירוע המרכזי על ידי החזרת true.

רכיב ההורה יכול ליירט את אירוע המקש שמתרחש ברכיבי הצאצא שלו. בקטע הקוד הבא, הפונקציה previewSKey() נקראת כשהמשתמשים לוחצים על המקש S, במקום לקרוא לפונקציה actionForPreview().

Column(
    modifier = Modifier.onPreviewKeyEvent {
        if (it.key == Key.S) {
            previewSKey()
            true
        } else {
            false
        }
    }
) {
    Box(
        modifier = Modifier
            .focusable()
            .onPreviewKeyEvent {
                actionForPreview(it)
                false
            }
            .onKeyEvent {
                actionForKeyEvent(it)
                true
            }
    ) {
        Text("Press any key")
    }
}

ה-lambda של onPreviewKeyEvent() לרכיב Box לא מופעלת גם כשמשתמשים לוחצים על המקש Tab. הפונקציה onPreviewKeyEvent() lambda נקראת קודם ברכיב האב, ואז נקראת הפונקציה onPreviewKeyEvent() ברכיב הבן. כדי להטמיע מקשי קיצור לכל המסך, אפשר להשתמש בהתנהגות הזו.

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

  • עזרה במקשי קיצור: מסך מערכת שמאפשר למשתמשים לחפש את מקשי הקיצור שהאפליקציה מציעה.