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

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

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

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

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

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

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

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

Box(
    modifier = Modifier.focusable().onKeyEvent {
        if(
            it.type == KeyEventType.KeyUp &&
            it.key == Key.S
        ) {
            doSomething()
            true
        } else {
            false
        }
    }
)  {
    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 על ידי טיפול באירועי קליקים באופן הבא:

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

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

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