יצירת הטמעה עם ממשקי API ישנים

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

בחירת פתרון חלופי

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

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

  • אפשר להטמיע כרטיסיות בסרגל הפעולות באמצעות LinearLayout אופקי שמכיל כפתורים, או באמצעות רכיב ממשק המשתמש TabWidget.

  • אפשר להטמיע את הווידג'טים NumberPicker ו-Switch באמצעות הווידג'טים Spinner ו-ToggleButton, בהתאמה.

  • אפשר להטמיע ווידג'טים של ListPopupWindow ושל PopupMenu באמצעות ווידג'טים של PopupWindow.

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

הטמעה של כרטיסיות באמצעות ממשקי API ישנים יותר

כדי ליצור הטמעה ישנה יותר של כרטיסיות בסרגל הפעולות, אפשר להשתמש ב-TabWidget וב-TabHost (אפשר גם להשתמש בווידג'טים של Button עם פריסה אופקית). צריך להטמיע את זה במחלקות שנקראות TabHelperEclair ו-CompatTabEclair, כי ההטמעה הזו משתמשת בממשקי API שהושקו לכל המאוחר ב-Android 2.0 (Eclair).

תרשים מחלקות להטמעה של כרטיסיות ב-Eclair.
איור 1. תרשים מחלקות להטמעה של כרטיסיות ב-Eclair.

ההטמעה של CompatTabEclair מאחסנת מאפיינים של כרטיסיות, כמו הטקסט והסמל של הכרטיסייה, במשתני מופע, כי אין אובייקט ActionBar.Tab שזמין לטיפול באחסון הזה:

Kotlin

class CompatTabEclair internal constructor(val activity: FragmentActivity, tag: String) :
        CompatTab(tag) {

    // Store these properties in the instance,
    // as there is no ActionBar.Tab object.
    private var text: CharSequence? = null
    ...

    override fun setText(resId: Int): CompatTab {
        // Our older implementation simply stores this
        // information in the object instance.
        text = activity.resources.getText(resId)
        return this
    }

    ...
    // Do the same for other properties (icon, callback, etc.)
}

Java

public class CompatTabEclair extends CompatTab {
    // Store these properties in the instance,
    // as there is no ActionBar.Tab object.
    private CharSequence text;
    ...

    public CompatTab setText(int resId) {
        // Our older implementation simply stores this
        // information in the object instance.
        text = activity.getResources().getText(resId);
        return this;
    }

    ...
    // Do the same for other properties (icon, callback, etc.)
}

ההטמעה של TabHelperEclair משתמשת בשיטות בווידג'ט TabHost כדי ליצור אובייקטים של TabHost.TabSpec ומחווני כרטיסיות:

Kotlin

class TabHelperEclair internal constructor(activity: FragmentActivity) : TabHelper(activity) {

    private var tabHost: TabHost? = null
    ...

    override fun setUp() {
        // Our activity layout for pre-Honeycomb devices
        // must contain a TabHost.
        tabHost = tabHost ?: mActivity.findViewById<TabHost>(android.R.id.tabhost).apply {
            setup()
        }
    }

    override fun addTab(tab: CompatTab) {
        ...
        tabHost?.newTabSpec(tab.tag)?.run {
            setIndicator(tab.getText()) // And optional icon
            ...
            tabHost?.addTab(this)
        }
    }
    // The other important method, newTab() is part of
    // the base implementation.
}

Java

public class TabHelperEclair extends TabHelper {
    private TabHost tabHost;
    ...

    protected void setUp() {
        if (tabHost == null) {
            // Our activity layout for pre-Honeycomb devices
            // must contain a TabHost.
            tabHost = (TabHost) mActivity.findViewById(
                    android.R.id.tabhost);
            tabHost.setup();
        }
    }

    public void addTab(CompatTab tab) {
        ...
        TabSpec spec = tabHost
                .newTabSpec(tag)
                .setIndicator(tab.getText()); // And optional icon
        ...
        tabHost.addTab(spec);
    }

    // The other important method, newTab() is part of
    // the base implementation.
}

עכשיו יש לכם שתי הטמעות של CompatTab ו-TabHelper: אחת שפועלת במכשירים עם Android מגרסה 3.0 ואילך ומשתמשת בממשקי API חדשים, ואחת שפועלת במכשירים עם Android מגרסה 2.0 ואילך ומשתמשת בממשקי API ישנים יותר. בשיעור הבא נדון בשימוש בהטמעות האלה באפליקציה.