יצירה של שיטת קלט

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

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

בדף הזה מפורטים הנושאים הבאים:

אם לא עבדתם עם IMEs, מומלץ לקרוא קודם את מאמר המבוא שיטות קלט במסך.

מחזור החיים של IME

בתרשים הבא מתואר מחזור החיים של IME:

תמונה שבה מוצג מחזור החיים של IME.
איור 1. מחזור החיים של IME.

בקטעים הבאים מוסבר איך להטמיע את ממשק המשתמש ואת הקוד שמשויכים ל-IME שפועל לפי מחזור החיים הזה.

הצהרה על רכיבי IME במניפסט

במערכת Android, ‏ IME היא אפליקציה ל-Android שמכילה שירות IME מיוחד. בקובץ המניפסט של האפליקציה צריך להצהיר על השירות, לבקש את ההרשאות הנדרשות, לספק מסנן Intent שתואם לפעולה action.view.InputMethod ולספק מטא-נתונים שמגדירים את המאפיינים של ה-IME. בנוסף, כדי לספק ממשק הגדרות שמאפשר למשתמש לשנות את ההתנהגות של ה-IME, אפשר להגדיר פעילות 'הגדרות' שאפשר להפעיל מתוך הגדרות המערכת.

בקטע הקוד הבא מוצהר על שירות IME. היא מבקשת את ההרשאה BIND_INPUT_METHOD כדי לאפשר לשירות לקשר את ה-IME למערכת, מגדירה מסנן Intent שתואם לפעולה android.view.InputMethod ומגדירה מטא-נתונים עבור ה-IME:

<!-- Declares the input method service. -->
<service android:name="FastInputIME"
    android:label="@string/fast_input_label"
    android:permission="android.permission.BIND_INPUT_METHOD">
    <intent-filter>
        <action android:name="android.view.InputMethod" />
    </intent-filter>
    <meta-data android:name="android.view.im"
               android:resource="@xml/method" />
</service>

בקטע הקוד הבא מוצהרת פעילות ההגדרות של ה-IME. יש לו מסנן Intent עבור ACTION_MAIN שמציין שהפעילות הזו היא נקודת הכניסה הראשית לאפליקציית ה-IME:

<!-- Optional: an activity for controlling the IME settings. -->
<activity android:name="FastInputIMESettings"
    android:label="@string/fast_input_settings">
    <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
    </intent-filter>
</activity>

אפשר גם לספק גישה להגדרות של ה-IME ישירות מממשק המשתמש שלו.

ה-API של שיטת הקלט

המחלקות שספציפיות ל-IME נמצאות בחבילות android.inputmethodservice ו-android.view.inputmethod. המחלקות KeyEvent חשובות לטיפול בתווים במקלדת.

החלק המרכזי של IME הוא רכיב שירות – מחלקה שמרחיבה את InputMethodService. בנוסף להטמעה של מחזור החיים הרגיל של השירות, למחלקה הזו יש קריאות חוזרות (callbacks) לאספקת ממשק המשתמש של ה-IME, לטיפול בקלט של המשתמש ולהעברת טקסט לשדה שמוגדר כברירת מחדל. כברירת מחדל, המחלקה InputMethodService מספקת את רוב ההטמעה לניהול הסטטוס והחשיפה של ה-IME ולתקשורת עם שדה הקלט הנוכחי.

גם המחלקות הבאות חשובות:

BaseInputConnection
הגדרת ערוץ התקשורת מ-InputMethod בחזרה לאפליקציה שמקבלת את הקלט שלה. משתמשים בו כדי לקרוא טקסט מסביב לסמן, להוסיף טקסט לתיבת הטקסט ולשלוח אירועים גולמיים של מקשים לאפליקציה. האפליקציות צריכות להרחיב את המחלקה הזו במקום להטמיע את ממשק הבסיס InputConnection.
KeyboardView
הרחבה של View שמעבדת מקלדת ומגיבה לאירועי קלט של משתמשים. פריסת המקלדת מוגדרת על ידי מופע של Keyboard, שאפשר להגדיר בקובץ XML.

עיצוב ממשק המשתמש של שיטת הקלט

יש שני רכיבים חזותיים עיקריים ל-IME: תצוגת הקלט ותצוגת המועמדים. צריך להטמיע רק את הרכיבים שרלוונטיים לשיטת הקלט שאתם מתכננים.

תצוגת הקלט

תצוגת הקלט היא ממשק המשתמש שבו המשתמש מזין טקסט בצורה של הקשות על מקשים, כתב יד או תנועות. כש-IME מוצג בפעם הראשונה, המערכת קוראת ל-callback‏ onCreateInputView(). בהטמעה של השיטה הזו, יוצרים את הפריסה שרוצים להציג בחלון של IME ומחזירים את הפריסה למערכת. בקטע הקוד הבא אפשר לראות דוגמה להטמעה של המתודה onCreateInputView():

Kotlin

override fun onCreateInputView(): View {
    return layoutInflater.inflate(R.layout.input, null).apply {
        if (this is MyKeyboardView) {
            setOnKeyboardActionListener(this@MyInputMethod)
            keyboard = latinKeyboard
        }
    }
}

Java

@Override
public View onCreateInputView() {
    MyKeyboardView inputView =
        (MyKeyboardView) getLayoutInflater().inflate(R.layout.input, null);

    inputView.setOnKeyboardActionListener(this);
    inputView.setKeyboard(latinKeyboard);

    return inputView;
}

בדוגמה הזו, MyKeyboardView הוא מופע של הטמעה מותאמת אישית של KeyboardView שמעבדת Keyboard.

תצוגת המועמדים

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

שיקולים בעיצוב ממשק המשתמש

בקטע הזה מתוארים כמה שיקולים לעיצוב ממשק משתמש עבור IMEs.

טיפול בכמה גדלים של מסכים

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

טיפול בסוגים שונים של קלט

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

לדוגמה, זה הממשק ש-IME ללטינית מספק להזנת טקסט בפלטפורמת Android:

תמונה שמראה קלט טקסט ב-IME ללטינית
איור 2. קלט טקסט של IME ללטינית.

זוהי הממשק ש-Latin IME מספק לקלט מספרי בפלטפורמת Android:

תמונה שמראה קלט מספרי ב-IME ללטינית
איור 3. קלט מספרי של IME לטיני.

כששדה להזנת קלט מקבל מיקוד וה-IME מתחיל, המערכת קוראת ל-onStartInputView(), ומעבירה אובייקט EditorInfo שמכיל פרטים על סוג הקלט ומאפיינים אחרים של שדה הטקסט. באובייקט הזה, השדה inputType מכיל את סוג הקלט של שדה הטקסט.

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

Kotlin

inputType and InputType.TYPE_MASK_CLASS

Java

inputType & InputType.TYPE_MASK_CLASS

תבנית הביטים של סוג הקלט יכולה לקבל כמה ערכים, כולל:

TYPE_CLASS_NUMBER
שדה טקסט להזנת מספרים. כפי שמודגם באיור 3, בממשק IME ללטינית מוצגת מקלדת מספרים לשדות מהסוג הזה.
TYPE_CLASS_DATETIME
שדה טקסט להזנת תאריך ושעה.
TYPE_CLASS_PHONE
שדה טקסט להזנת מספרי טלפון.
TYPE_CLASS_TEXT
שדה טקסט להזנת תווים נתמכים.

הקבועים האלה מתוארים בפירוט במאמרי העזרה של InputType.

השדה inputType יכול להכיל חלקים אחרים שמציינים וריאציה של סוג שדה הטקסט, כמו:

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

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

שליחת טקסט לאפליקציה

בזמן שהמשתמש מזין טקסט באמצעות ה-IME, אתם יכולים לשלוח טקסט לאפליקציה על ידי שליחת אירועי מקשים בודדים או על ידי עריכת הטקסט סביב הסמן בשדה הטקסט של האפליקציה. בכל מקרה, צריך להשתמש במופע של InputConnection כדי להעביר את הטקסט. כדי לקבל את המופע הזה, צריך להתקשר אל InputMethodService.getCurrentInputConnection().

עריכת הטקסט מסביב לסמן

כשעורכים טקסט קיים, אפשר להשתמש בשיטות הבאות ב-BaseInputConnection:

getTextBeforeCursor()
מחזירה CharSequence עם מספר התווים המבוקש לפני מיקום הסמן הנוכחי.
getTextAfterCursor()
מחזירה CharSequence שמכילה את מספר התווים המבוקש אחרי מיקום הסמן הנוכחי.
deleteSurroundingText()
מחיקת מספר התווים שצוין לפני ואחרי המיקום הנוכחי של הסמן.
commitText()
Commits a CharSequence to the text field and sets a new cursor position.

לדוגמה, בקטע הקוד הבא מוצג איך להחליף את ארבעת התווים שמשמאל לסמן בטקסט 'Hello!':

Kotlin

currentInputConnection.also { ic: InputConnection ->
    ic.deleteSurroundingText(4, 0)
    ic.commitText("Hello", 1)
    ic.commitText("!", 1)
}

Java

InputConnection ic = getCurrentInputConnection();
ic.deleteSurroundingText(4, 0);
ic.commitText("Hello", 1);
ic.commitText("!", 1);

תמיכה בכתיבת טקסט לפני השמירה

אם ה-IME חוזה טקסט או דורש כמה שלבים כדי ליצור גליף או מילה, אפשר להציג את ההתקדמות בשדה הטקסט עד שהמשתמש מאשר את המילה, ואז להחליף את החלק מהמילה בטקסט המלא. אפשר להוסיף לטקסט span כשמעבירים אותו אל setComposingText() כדי להחיל עליו עיצוב מיוחד.

בקטע הקוד הבא אפשר לראות איך מציגים את ההתקדמות בשדה טקסט:

Kotlin

currentInputConnection.also { ic: InputConnection ->
    ic.setComposingText("Composi", 1)
    ic.setComposingText("Composin", 1)
    ic.commitText("Composing ", 1)
}

Java

InputConnection ic = getCurrentInputConnection();
ic.setComposingText("Composi", 1);
ic.setComposingText("Composin", 1);
ic.commitText("Composing ", 1);

יירוט אירועים מרכזיים של ציוד

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

כדי ליירט מקשי חומרה, צריך לבטל את ההגדרה של onKeyDown() ושל onKeyUp().

מבצעים קריאה ל-super() לגבי מפתחות שלא רוצים לטפל בהם בעצמכם.

יצירת סוג משנה של IME

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

  • לוקאל, כמו en_US או fr_FR
  • מצב קלט, כמו קול, מקלדת או כתב יד
  • סגנונות קלט אחרים, טפסים או מאפיינים ספציפיים ל-IME, כמו פריסות מקלדת של 10 מקשים או QWERTY

המצב יכול להיות כל טקסט, כמו 'מקלדת' או 'קול'. סוג משנה יכול גם לחשוף שילוב של אלה.

המידע על סוג המשנה משמש לתיבת דו-שיח להחלפת IME שזמינה מסרגל ההתראות ולהגדרות IME. המידע גם מאפשר למסגרת להציג ישירות סוג משנה ספציפי של IME. כשמפתחים IME, מומלץ להשתמש בתכונת סוג המשנה, כי היא עוזרת למשתמש לזהות את השפות והמצבים השונים של ה-IME ולעבור ביניהם.

מגדירים תת-סוגים באחד מקובצי משאבי ה-XML של שיטת הקלט, באמצעות הרכיב <subtype>. בקטע הקוד הבא מוגדר IME עם שני סוגי משנה: סוג משנה של מקלדת ללוקאל של אנגלית (ארה"ב) וסוג משנה נוסף של מקלדת ללוקאל של השפה הצרפתית בצרפת:

<input-method xmlns:android="http://schemas.android.com/apk/res/android"
        android:settingsActivity="com.example.softkeyboard.Settings"
        android:icon="@drawable/ime_icon">
    <subtype android:name="@string/display_name_english_keyboard_ime"
            android:icon="@drawable/subtype_icon_english_keyboard_ime"
            android:languageTag="en-US"
            android:imeSubtypeMode="keyboard"
            android:imeSubtypeExtraValue="somePrivateOption=true" />
    <subtype android:name="@string/display_name_french_keyboard_ime"
            android:icon="@drawable/subtype_icon_french_keyboard_ime"
            android:languageTag="fr-FR"
            android:imeSubtypeMode="keyboard"
            android:imeSubtypeExtraValue="someVariable=30,someInternalOption=false" />
    <subtype android:name="@string/display_name_german_keyboard_ime" ... />
</input-method>

כדי לוודא שסוגי המשנה מתויגים בצורה נכונה בממשק המשתמש, צריך להשתמש ב-‎%s כדי לקבל תווית של סוג משנה שזהה לתווית הלוקאל של סוג המשנה. שתי הדוגמאות הבאות לקטעי קוד ממחישות את זה. בקטע הקוד הראשון מוצג חלק מקובץ ה-XML של שיטת הקלט:

<subtype
    android:label="@string/label_subtype_generic"
    android:imeSubtypeLocale="en_US"
    android:icon="@drawable/icon_en_us"
    android:imeSubtypeMode="keyboard" />

הקטע הבא הוא חלק מקובץ strings.xml של ה-IME. משאב המחרוזות label_subtype_generic, שמשמש להגדרת ממשק המשתמש של שיטת הקלט כדי להגדיר את התווית של סוג המשנה, מוגדר באופן הבא:

<string name="label_subtype_generic">%s</string>

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

בחירת סוגי משנה של IME מסרגל ההתראות

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

תמונה שרואים בה את תפריט המערכת 'שפות וקלט'
איור 4. תפריט המערכת שפות וקלט.

בחירה של סוגי משנה של IME מתוך הגדרות המערכת

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

תמונה שבה מוצג התפריט לבחירת שפות
איור 5. תפריט המערכת שפות

מעבר בין סוגי משנה של IME

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

  1. מצהירים על supportsSwitchingToNextInputMethod = "true" בקובצי המשאבים בפורמט XML של שיטת הקלט. ההצהרה שלכם צריכה להיראות כמו קטע הקוד הבא:
    <input-method xmlns:android="http://schemas.android.com/apk/res/android"
            android:settingsActivity="com.example.softkeyboard.Settings"
            android:icon="@drawable/ime_icon"
            android:supportsSwitchingToNextInputMethod="true">
  2. מבצעים קריאה ל-shouldOfferSwitchingToNextInputMethod().
  3. אם השיטה מחזירה true, מוצג מקש מעבר.
  4. כשהמשתמש מקיש על מקש ההחלפה, השיחה switchToNextInputMethod(), מועברת כ-false. הערך false אומר למערכת להתייחס לכל סוגי המשנה באופן שווה, בלי קשר ל-IME שאליהם הם שייכים. אם מציינים True, המערכת עוברת בין סוגי משנה ב-IME הנוכחי.

שיקולים כלליים לגבי IME

אלה עוד דברים שכדאי לקחת בחשבון כשמטמיעים את ה-IME:

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