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

כשהמשתמש מתמקד ברכיב טקסט שניתן לעריכה, כמו 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

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

ב-Compose, אפשר לטפל בלחיצה בודדת על מקש באמצעות המשתנה 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

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

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

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