עיצוב רספונסיבי/מותאם אישית עם תצוגות

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

עיצוב דינמי

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

פריסת אילוצים

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

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

איור 3. בעורך הפריסה ב-Android Studio רואים ConstraintLayout

למידע נוסף, ראו בניית ממשק משתמש רספונסיבי עם פריסת אילוצים.

רוחב וגובה של מודעות רספונסיביות

כדי לוודא שהפריסה שלך רספונסיבית לגדלים שונים של מסכים, משתמשים wrap_content, match_parent או 0dp (match constraint) לרוחב ול גובה רכיבי התצוגה במקום ערכים הכתובים בתוך הקוד:

  • wrap_content: התצוגה קובעת את גודלה כך שיתאים לתוכן בתצוגה.
  • match_parent: התצוגה מתרחבת ככל האפשר בתצוגת ההורה.
  • 0dp (match constraint): בConstraintLayout, בדומה ל- match_parent. התצוגה תופסת את כל השטח הזמין מגבלות בפועל.

לדוגמה:

<TextView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="@string/lorem_ipsum" />

איור 4 מראה איך הרוחב והגובה של TextView משתנים בתור התצוגה הרוחב משתנה בהתאם לכיוון המכשיר.

איור 4. TextView רספונסיבי.

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

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

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

עיצוב דינמי

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

SlidingPaneLayouts לממשקי משתמש עם פרטי רשימה

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

SlidingPaneLayout שמנהל את הלוגיקה שקובעת איזו משתי חוויות המשתמש מתאים לגודל החלון הנוכחי:

<?xml version="1.0" encoding="utf-8"?>
<androidx.slidingpanelayout.widget.SlidingPaneLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="280dp"
        android:layout_height="match_parent"
        android:layout_gravity="start" />

    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="300dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        app:defaultNavHost="true"
        app:navGraph="@navigation/item_navigation" />

</androidx.slidingpanelayout.widget.SlidingPaneLayout>

המאפיינים layout_width ו-layout_weight של שתי התצוגות המפורטות שכלולות הפונקציה SlidingPaneLayout קובעת את ההתנהגות SlidingPaneLayout. בדוגמה, אם החלון גדול מספיק (ברוחב של 580dp לפחות) כדי להציג את שתי התצוגות, החלוניות מוצגות זו לצד זו. אבל אם רוחב החלון קטן מ- ב-580dp, החלוניות מחליקים זו על זו כדי למלא את כל האפליקציה בנפרד חלון.

אם רוחב החלון גדול מהרוחב המינימלי הכולל שצוין (580dp), אפשר להשתמש בערכים של layout_weight כדי לשנות את הגודל של שתי החלוניות באופן פרופורציונלי. ב לדוגמה, חלונית הרשימה תמיד ברוחב 280dp כי אין לה משקל. עם זאת, חלונית הפרטים תמיד ממלאת כל שטח אופקי מעבר ל-580dp של הגדרת layout_weight של התצוגה.

מקורות מידע לפריסות חלופיות

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

איור 5. אותה אפליקציה משתמשת בפריסות שונות לגדלי תצוגה שונים.

כדי לספק פריסות שמותאמות למסך באופן אוטומטי, אפשר ליצור פריסות נוספות ספריות res/layout/ בקוד המקור של האפליקציה. צריך ליצור ספרייה לכל אחד מהם להגדרת מסך שדורשת פריסה שונה. לאחר מכן צריך להוסיף מסך תוחם התצורה לשם הספרייה layout (לדוגמה, layout-w600dp למסכים עם רוחב זמין של 600dp).

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

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

תוחם הרוחב הקטן ביותר

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

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

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

res/layout/main_activity.xml           # For phones (smaller than 600dp smallest width)
res/layout-sw600dp/main_activity.xml   # For 7" tablets (600dp wide or wider)

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

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

  • 320dp: מסך טלפון קטן (240x320 ldpi , 320x480 mdpi , 480x800 hdpi וכו')
  • 480dp: מסך טלפון גדול בגודל 5 אינץ' (480x800 mdpi)
  • 600dp: 7 אינץ' טאבלט (600x1024 mdpi)
  • 720dp: 10 אינץ' טאבלט (720x1280 mdpi , 800x1280 mdpi וכו')

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

איור 6. נקודות עצירה מומלצות ברוחב כדי לתמוך בגדלים שונים.

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

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

תוחם רוחב זמין

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

res/layout/main_activity.xml         # For phones (smaller than 600dp available width)
res/layout-w600dp/main_activity.xml  # For 7" tablets or any screen with 600dp available width
                                     # (possibly landscape phones)

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

מגדירים כיוון

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

לשם כך, ניתן להוסיף את המפרידים port או land לספריית הפריסה שמות. חשוב לוודא שערכי הכיוון מופיעים אחרי ערכי הגודל. לדוגמה:

res/layout/main_activity.xml                # For phones
res/layout-land/main_activity.xml           # For phones in landscape
res/layout-sw600dp/main_activity.xml        # For 7" tablets
res/layout-sw600dp-land/main_activity.xml   # For 7" tablets in landscape

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

סיווגי גודל של חלונות

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

כדי להחיל פריסות מותאמות באופן פרוגרמטי:

  • יצירת משאבי פריסה על סמך נקודות העצירה (breakpoint) של סיווג גודל החלון
  • מחשבים את סיווגי הגודל של חלונות הרוחב והגובה של האפליקציה באמצעות WindowSizeClass#compute() מ-Jetpack windowManager ספרייה
  • ניפוח משאב הפריסה עבור סיווגי הגודל הנוכחיים של החלון

למידע נוסף, ראו גודל חלון סיווגים.

רכיבים בממשק משתמש מודולרי באמצעות מקטעים

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

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

למידע נוסף, אפשר לעיין בסקירה הכללית על מקטעים.

הטמעת פעילויות

אם האפליקציה כוללת מספר פעילויות, הטמעת פעילויות מאפשרת לך ליצור ממשק משתמש מותאם.

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

אפשר לקבוע איך האפליקציה מציגה את הפעילויות שלה על ידי יצירת קובץ XML את קובץ התצורה שבו המערכת משתמשת כדי לקבוע על סמך גודל התצוגה. אפשר גם ליצור Jetpack ממשק ה-API של windowManager שיחות.

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

מידע נוסף זמין בקטע פעילות הטמעה.

גודל המסך ויחס הגובה-רוחב

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

מכשירי Android 10 (רמת API 29) ואילך תומכים במגוון רחב של יחסי גובה-רוחב. גורמי צורה מתקפלים יכולים להיות שונים ממסכים גבוהים וצרים, למשל 21:9 במצב מקופל, ביחס גובה-רוחב של 1:1 במצב פתוח.

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

איור 7. יחסי גובה-רוחב שונים של המסך.

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

אם אתם מעדיפים לבצע בדיקה במכשיר אמיתי אבל המכשיר לא נמצא אצלכם, תוכלו להשתמש Firebase Test Lab כדי לגשת במרכז הנתונים של Google.

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