סקירה כללית של אירועי קלט

רוצה לנסות את שיטת הכתיבה?
'Jetpack פיתוח נייטיב' היא ערכת הכלים המומלצת לממשק המשתמש ל-Android. מידע נוסף על שימוש בנגיעה ובקלט במהלך 'כתיבה'.

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

במחלקות השונות של View (View) שבהן משתמשים כדי לכתוב את הפריסה, יכול להיות שיופיעו כמה קריאות חוזרות (callback) ציבוריות שיטות שנראות שימושיות לאירועים בממשק המשתמש. ל-methods האלה מתבצעת קריאה ב-framework של Android, הפעולה המתאימה מתרחשת על האובייקט. לדוגמה, כשנוגעים בתצוגה (כגון לחצן), בוצעה קריאה ל-method onTouchEvent() באובייקט הזה. עם זאת, כדי ליירט אותו, צריך להאריך את התוקף המחלקה ומשנים את השיטה. עם זאת, הרחבת כל אובייקט מסוג View פתרון אירוע כזה אינו מעשי. לכן הכיתה 'צפייה' כוללת גם אוסף של ממשקים בתוך ממשקים עם קריאות חוזרות (callback) שאפשר להגדיר בקלות רבה יותר. הממשקים האלה שנקראים event listeners, הם הכרטיס שלכם לתיעוד האינטראקציה של המשתמש עם ממשק המשתמש.

אמנם בדרך כלל תשתמשו ב-event listener כדי להקשיב לאינטראקציה של משתמשים, אבל כאשר רוצים להרחיב כיתה מסוג 'צפייה' כדי לבנות רכיב מותאם אישית. אולי כדאי להאריך את Button? כדי ליצור משהו מפואר יותר. במקרה הזה תוכלו להגדיר את התנהגויות ברירת המחדל של האירועים עבור class באמצעות המחלקה רכיבי handler של אירועים.

פונקציות event listener

event listener הוא ממשק במחלקה View שמכיל מקטע אחד שיטת קריאה חוזרת. ל-methods אלה תיקרא מסגרת Android כשהתצוגה המפורטת שאליה המאזינים רשום מופעל על ידי אינטראקציה של המשתמש עם הפריט בממשק המשתמש.

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

onClick()
החל מ-View.OnClickListener. מתבצעת קריאה כאשר המשתמש נוגע בפריט (במצב מגע), או מתמקד בפריט באמצעות מקשי הניווט או כדור העקיבה לוחץ על מקש ה-"Enter" המתאים מקש או לוחץ על כדור העקיבה.
onLongClick()
החל מ-View.OnLongClickListener. מתבצעת קריאה כאשר המשתמש לוחץ ומחזיק בפריט (במצב מגע), או מתמקד בפריט עם מקשי הניווט או כדור העקיבה לוחץ לחיצה ארוכה על ה-"Enter" המתאים מקש או לוחץ לחיצה ארוכה על כדור העקיבה (למשך שנייה אחת).
onFocusChange()
החל מ-View.OnFocusChangeListener. הקריאה הזו מופעלת כשהמשתמש מנווט אל הפריט או מתרח ממנו באמצעות מקשי הניווט או כדור העקיבה.
onKey()
החל מ-View.OnKeyListener. הקריאה הזו מופעלת כשהמשתמש ממוקד בפריט ולוחץ על מקש חומרה במכשיר או משחרר אותו.
onTouch()
החל מ-View.OnTouchListener. מתבצעת קריאה לפעולה הזו כשהמשתמש מבצע פעולה שמתאימה לאירוע מגע, כולל לחיצה, הודעה, או כל תנועת תנועה במסך (בגבולות הפריט).
onCreateContextMenu()
החל מ-View.OnCreateContextMenuListener. הפעולה הזו נקראת כשתפריט הקשר נוצר (כתוצאה מ'קליק ארוך' ממושך). הצגת הדיון בתפריטי ההקשר בתפריטים המדריך למפתחים.

שיטות אלה הן התושבות היחידות בממשק התואם. כדי להגדיר אחת מהשיטות האלה ולטפל באירועים שלכם, להטמיע את הממשק הפנימי בפעילות שלכם או להגדיר אותו ככיתה אנונימית. לאחר מכן, מעבירים מופע של ההטמעה ל-method המתאים של View.set...Listener(). (לדוגמה: setOnClickListener() ולהעביר אליה את ההטמעה של OnClickListener).

הדוגמה הבאה מראה איך לרשום לחצן בהאזנה בלחיצה.

Kotlin

protected void onCreate(savedValues: Bundle) {
    ...
    val button: Button = findViewById(R.id.corky)
    // Register the onClick listener with the implementation above
    button.setOnClickListener { view ->
        // do something when the button is clicked
    }
    ...
}

Java

// Create an anonymous implementation of OnClickListener
private OnClickListener corkyListener = new OnClickListener() {
    public void onClick(View v) {
      // do something when the button is clicked
    }
};

protected void onCreate(Bundle savedValues) {
    ...
    // Capture our button from layout
    Button button = (Button)findViewById(R.id.corky);
    // Register the onClick listener with the implementation above
    button.setOnClickListener(corkyListener);
    ...
}

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

Kotlin

class ExampleActivity : Activity(), OnClickListener {
  
    protected fun onCreate(savedValues: Bundle) {
        val button: Button = findViewById(R.id.corky)
        button.setOnClickListener(this)
    }

    // Implement the OnClickListener callback
    fun onClick(v: View) {
        // do something when the button is clicked
    }
}

Java

public class ExampleActivity extends Activity implements OnClickListener {
    protected void onCreate(Bundle savedValues) {
        ...
        Button button = (Button)findViewById(R.id.corky);
        button.setOnClickListener(this);
    }

    // Implement the OnClickListener callback
    public void onClick(View v) {
      // do something when the button is clicked
    }
    ...
}

שימו לב שהקריאה החוזרת (callback) של onClick() בדוגמה שלמעלה אין ערך מוחזר, אבל חלק מהשיטות האחרות של האזנה לאירועים חייבות להחזיר ערך בוליאני. הסיבה תלוי באירוע. זו הסיבה לכך:

  • onLongClick() – הפונקציה מחזירה ערך בוליאני כדי לציין אם צריך את האירוע ואין להעביר אותו הלאה. כלומר, הפונקציה מחזירה את הערך true כדי לציין שטיפלתם באירוע והוא צריך להסתיים כאן. הפונקציה מחזירה את הערך false אם לא טיפלתם בו ו/או שהאירוע אמור להמשיך לערוץ אחר. מאזינים בלחיצה.
  • onKey() – הפונקציה מחזירה ערך בוליאני כדי לציין אם צריך את האירוע ואין להעביר אותו הלאה. כלומר, הפונקציה מחזירה את הערך true כדי לציין שטיפלתם באירוע והוא צריך להסתיים כאן. הפונקציה מחזירה את הערך false אם לא טיפלתם בו ו/או שהאירוע אמור להמשיך לערוץ אחר. מאזיני מפתח.
  • onTouch() – הפונקציה מחזירה ערך בוליאני כדי לציין אם ה-listener משתמש באירוע הזה. הדבר החשוב הוא האירוע הזה יכול לכלול מספר פעולות שעוקבות זו אחרי זו. לכן, אם תחזירו את הערך false כאשר התקבל אירוע של פעולה מושבתת, אתה מציין שלא צרכת את האירוע ו אין לי עניין בפעולות נוספות מאירוע זה. לכן, לא תתבקשו לבצע פעולות אחרות בתוך האירוע, למשל תנועה באצבע או האירוע של הפעולה הסופית.

חשוב לזכור שאירועים מרכזיים בחומרה תמיד נשלחים לתצוגה שבה אתם מתמקדים. הם נשלחים מההתחלה ועד הסוף של היררכיית התצוגה, ואז למטה, עד שהם מגיעים ליעד המתאים. אם התצוגה המפורטת שלך (או צאצא של התצוגה המפורטת שלך) כרגע מוגדר מיקוד, אז אפשר לראות את המעבר של האירוע באמצעות השיטה dispatchKeyEvent(). כחלופה לתיעוד אירועים מרכזיים דרך התצוגה, אפשר גם לקבל כל האירועים בתוך הפעילות שלך עם onKeyDown() ו-onKeyUp().

כמו כן, כאשר חושבים על קלט טקסט לאפליקציה, חשוב לזכור שמכשירים רבים כוללים רק קלט תוכנה שיטות. שיטות כאלה לא חייבות להיות מבוססות-מפתח. חלקם עשויים להשתמש בקלט קולי, בכתב יד וכן הלאה. גם אם ששיטת קלט מציגה ממשק דמוי מקלדת, היא בדרך כלל לא מפעילה את משפחת אירועים אחת (onKeyDown()). אף פעם לפתח ממשק משתמש שמחייב שליטה על מקשים ספציפיים, אלא אם רוצים להגביל את האפליקציה למכשירים עם מקלדת חומרה. בפרט, אין להסתמך על השיטות האלה כדי לאמת קלט כשהמשתמש לוחץ על מפתח החזרה; במקום זאת, יש להשתמש בפעולות כמו IME_ACTION_DONE כדי לסמן של שיטת הקלט לגבי האופן שבו האפליקציה מצפה להגיב, לכן היא עשויה לשנות את ממשק המשתמש שלה בצורה משמעותית. הימנעות מהנחות על האופן שבו שיטת קלט של תוכנה אמורה לפעול, ופשוט סומכים עליה שהיא תספק לאפליקציה שלכם טקסט שכבר מעוצב.

הערה: מערכת Android תפעיל קודם את הגורמים המטפלים באירועים ולאחר מכן את ברירת המחדל המתאימה את ה-handlers של הגדרת הסיווג, לכן, החזרת הערך true של פונקציות event listener תופסק הפצת האירוע למאזינים אחרים של האירוע וגם תחסום את הקריאה החוזרת אל הגורם המטפל באירועים שמוגדר כברירת מחדל בתצוגה. לכן, חשוב לוודא שמסיימים את האירוע כשמחזירים את הערך true.

גורמים מטפלים באירועים

אם יוצרים רכיב מותאם אישית מ'תצוגה', אפשר להגדיר כמה שיטות קריאה חוזרת (callback) שמשמש כברירת מחדל כגורמים מטפלים באירועים. במסמך בנושא Custom צפייה ברכיבים, תלמדו על כמה מהקריאות החוזרות (callback) הנפוצות שמשמשות לטיפול באירועים, כולל:

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

מצב מגע

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

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

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

מצב מצב המגע נשמר בכל המערכת (כל החלונות והפעילויות). כדי להריץ שאילתה על המצב הנוכחי, אפשר להתקשר isInTouchMode() כדי לבדוק אם המכשיר נמצא כרגע במצב מגע.

טיפול בפוקוס

תוכנת ה-framework תטפל בתנועת מיקוד שגרתית בתגובה לקלט של משתמשים. זה כולל שינוי המיקוד כתצוגות שהוסרו או מוסתרות, או כתצוגות חדשות תצוגות הנתונים יהיו זמינות. הצפיות מעידות על נכונותם להתמקד באמצעות method isFocusable(). כדי לקבוע אם תצוגה מפורטת יכולה לצלם פוקוס, התקשרות אל setFocusable(). במצב מגע, אפשר לשאול אם תצוגה מפורטת מאפשרת להתמקד ב-isFocusableInTouchMode(). אפשר לשנות את זה בחשבון של setFocusableInTouchMode().

במכשירים עם Android מגרסה 9 (רמת API 28) ואילך, הפעילויות לא מוקצות את המיקוד הראשוני. במקום זאת, אם תרצו, עליכם לבקש מיקוד ראשוני באופן מפורש.

תנועת המיקוד מבוססת על אלגוריתם שמוצא את השכן הקרוב ביותר כיוון נתון. במקרים נדירים, ייתכן שאלגוריתם ברירת המחדל לא יתאים ההתנהגות של המפתח. במצבים כאלה, אפשר לספק שינויים מפורשים במאפייני ה-XML הבאים בקובץ הפריסה: nextFocusDown, nextFocusLeft, nextFocusRight וגם nextFocusUp מוסיפים את אחד מהמאפיינים האלה לתצוגה המפורטת שממנו. המיקוד נעלם. מגדירים את ערך המאפיין כך שיהיה המזהה של התצוגה המפורטת שבו צריך להתמקד. לדוגמה:

<LinearLayout
    android:orientation="vertical"
    ... >
  <Button android:id="@+id/top"
          android:nextFocusUp="@+id/bottom"
          ... />
  <Button android:id="@+id/bottom"
          android:nextFocusDown="@+id/top"
          ... />
</LinearLayout>

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

אם אתם רוצים להצהיר שתצוגה מסוימת ניתנת למיקוד בממשק המשתמש (אם בדרך כלל היא לא ניתנת למיקוד), צריך להוסיף את מאפיין ה-XML מסוג android:focusable לתצוגה המפורטת, בהצהרת הפריסה. מגדירים את הערך true. אפשר גם להצהיר על צפייה שניתן להתמקד בהם במצב מגע עם android:focusableInTouchMode.

כדי לבקש להתמקד בתצוגה מסוימת, צריך להתקשר למספר requestFocus().

כדי להאזין לאירועי מיקוד (לקבל התראה כשתצוגה מקבלת או מאבדת את המיקוד), משתמשים onFocusChange(), כפי שצוין בקטע Event Listeners