מגבלות וסדר מגביל

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

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

גורמי שינוי בעץ של ממשק המשתמש

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

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

קוד לתכנים קומפוזביליים ומגבילים, והייצוג החזותי שלהם כעץ ממשק משתמש.
איור 1. מודификаторים שמקיפים צמתים של פריסה בעץ של ממשק המשתמש.

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

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

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

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

לסיכום:

  • מגבילי התאמה גורפים צומת של מקש צירוף או פריסה יחיד.
  • צמתים של פריסה יכולים לפרוס מספר צומתי צאצא.

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

מגבלות בשלב הפריסה

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

  1. מדידת הצאצאים: הצומת מודד את הצאצאים שלו, אם יש כאלה.
  2. קביעת הגודל בעצמו: על סמך המדידות האלה, הצומת קובע את הגודל שלו.
  3. מיקום הצאצאים: כל צומת צאצא ממוקם ביחס למיקום של הצומת עצמו.

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

סוגי האילוצים

אילוצים יכולים להיות מהסוגים הבאים:

  • מוגבל: לצומת יש רוחב וגובה מקסימליים ומינימליים.
אילוצים מוגבלים בגדלים שונים בתוך קונטיינר.
איור 3. מגבלות מוגבלות.
  • ללא גבולות: הצומת לא מוגבל לגודל כלשהו. הרוחב המקסימלי וגם גבולות הגובה מוגדרים לאינסוף.
אילוצים ללא גבול שבהם הרוחב והגובה מוגדרים כ-infinity. האילוצים נמשכים מעבר לקונטיינר.
איור 4. מגבלות בלתי מוגבלות.
  • מדויק: הצומת מתבקש לעמוד בדרישת גודל מדויקת. המינימום והגבולות המקסימליים מוגדרים לאותו ערך.
אילוצים מדויקים שתואמים לדרישת הגודל המדויק בתוך הקונטיינר.
איור 5. מגבלות מדויקות.
  • שילוב: הצומת פועל לפי שילוב של סוגי האילוצים שלמעלה. לדוגמה, אילוץ יכול להגביל את הרוחב ובמקביל לאפשר גובה מקסימלי בלתי מוגבל, או להגדיר רוחב מדויק אבל להגדיר גובה מוגבל.
שני מאגרים שמציגים שילובים של אילוצים מוגבלים ולא מוגבלים, ורוחב וגובה מדויקים.
איור 6. שילובים של מגבלות עם הגבלות, הגבלות עם הגבלות ורוחב מדויק וגבהים.

בקטע הבא מוסבר איך האילוצים האלה מועברים מהורה לצאצא.

איך מגבלות מועברות מהורה לילד

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

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

ככלל, האלגוריתם פועל באופן הבא:

  1. כדי לקבוע את הגודל בפועל שברצונך לתפוס, הצומת של הרמה הבסיסית (root) בעץ ממשק המשתמש ומודדת את הצאצאים שלו ומעבירה את אותן מגבלות אל הצאצא הראשון שלו.
  2. אם הצאצא הוא שינוי שלא משפיע על המדידה, הוא מעביר את האילוצים לשינוי הבא. המגבלות מועברות למטה רשת כפי שהיא, אלא אם מתקבל ערך לשינוי שמשפיע על המדידה. לאחר מכן, המערכת תשנה את הגודל של האילוצים בהתאם.
  3. כשמגיעים לצומת שאין לו צאצאים (נקרא "צומת עלה"), הוא קובע את הגודל שלו על סמך האילוצים שהועברו, ומחזיר את הגודל המחושב להורה שלו.
  4. ההורה משנה את המגבלות שלו בהתאם למדידות של הילד או הילדה, קורא לצאצא הבא עם המגבלות המותאמות האלה.
  5. לאחר שכל הצאצאים של הורה נמדדים, הצומת ההורה מחליט על בגודל האישי שלו, ומעביר אותו להורה שלו.
  6. כך כל העץ עובר סריקה לפי עומק. בסופו של דבר, כל הצמתים החליטה על גודלם, ושלב המדידה הושלם.

אפשר לראות דוגמה מפורטת יותר במאמר מגבלות וסדר מגביל. וידאו.

משתני אופן פעולה שמשפיעים על אילוצים

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

המשתנה size

הצירוף size מציין את הגודל המועדף של התוכן.

לדוגמה, יש ליצור את עץ ממשק המשתמש הבא בקונטיינר של 300dp על ידי 200dp. האילוצים הם במסגרת תחום, ומאפשרים רוחב בין 100dp ל- 300dp, ובגבהים בין 100dp ל-200dp:

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

מגביל size מתאים את המגבלות הנכנסות כך שיתאימו לערך שמועבר אליו. בדוגמה הזו, הערך הוא 150dp:

זהה לאיור 7, למעט עם שינוי הגודל שמאפשר להתאים את המגבלות הנכנסות כך שיתאימו לערך שמועבר אליו.
איור 8. המשתנה המשנה size שמתאים את האילוצים ל-150dp.

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

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

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

שרשרת של שני משתני גודל בעץ של ממשק המשתמש והייצוג שלה בקונטיינר, שהוא התוצאה של הערך הראשון שהוענק ולא של הערך השני.
איור 10. שרשרת של שני משתני size, שבה הערך השני שהוענק (50dp) לא מבטל את הערך הראשון (100dp).

המשתנה requiredSize

אם צריךrequiredSizesize כדי לעקוף את האילוצים הנכנסים. מקש הצירוף requiredSize מחליף את את המגבלות שהתקבלו ומעביר את הגודל שצוין כגבולות מדויקים.

כשהגודל מועבר חזרה בעץ, הצומת הצאצא יתרכז שטח פנוי:

מגביל הגודל והגודל הנדרש משורשרים בעץ ממשק משתמש,
  ייצוג בו-זמנית בקונטיינר. האילוצים של המאפיין requiredSize מבטלים את האילוצים של המאפיין size.
איור 11. מקש הצירוף requiredSize מבטל את האילוצים הנכנסים מ- מקש הצירוף size.

המשתנים width ו-height

המשתנה המשנה size מתאים את הרוחב והגובה של האילוצים. בעזרת המשתנה המשנה width אפשר להגדיר רוחב קבוע אבל להשאיר את הגובה לא מוגדר. באותו אופן, בעזרת הצירוף height אפשר להגדיר גובה קבוע, אבל להשאיר את רוחב לא קבוע:

שני עצים של ממשק המשתמש, אחד עם מקש הצירוף של הרוחב והייצוג של הקונטיינר שלו
  באמצעות מקש ההתאמה של הגובה והייצוג שלו.
איור 12. הגדרת התוספת של width ומקש הצירוף height של רוחב קבוע ו-גובה, בהתאמה.

ערך לשינוי בשדה sizeIn

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

עץ ממשק משתמש עם מקש הצירוף sizeIn עם ערכי רוחב וגובה מינימליים ומקסימליים,
  והייצוג שלו בתוך קונטיינר.
איור 13. המגביל sizeIn עם minWidth, maxWidth, minHeight ועם maxHeight הוגדר.

דוגמאות

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

Image(
    painterResource(R.drawable.hero),
    contentDescription = null,
    Modifier
        .fillMaxSize()
        .size(50.dp)
)

קטע הקוד הזה יפיק את הפלט הבא:

  • המאפיין fillMaxSize משנה את האילוצים כך שהרוחב והגובה המינימליים יוגדרו לערך המקסימלי – 300dp ברוחב ו-200dp בגובה.
  • גם אם המשתנה המשנה size רוצה להשתמש בגודל 50dp, הוא עדיין צריך לעמוד באילוצים המינימליים הנכנסים. לכן הצירוף size גם פלט את גבולות האילוץ המדויקים של 300 עד 200, באופן אפקטיבי תוך התעלמות מהערך שצוין בתכונת הצירוף size.
  • השדה Image תואם לגבולות האלה ומדווח על גודל של 300 עד 200, מועבר לאורך כל הדרך במעלה העץ.

Image(
    painterResource(R.drawable.hero),
    contentDescription = null,
    Modifier
        .fillMaxSize()
        .wrapContentSize()
        .size(50.dp)
)

קטע הקוד הזה יפיק את הפלט הבא:

  • מגביל fillMaxSize מתאים את המגבלות כדי להגדיר גם הרוחב והגובה לערך המקסימלי — 300dp ברוחב ו-200dp אינץ' גובה.
  • מקש הצירוף wrapContentSize מאפס את המגבלות המינימליות. לכן, בעוד ש-fillMaxSize גרם להגבלות קבועות, wrapContentSize מאפס אותו חזרה להגבלות מוגבלות. הצומת הבא יכול עכשיו לתפוס את כל השטח שוב, או להיות קטן יותר מכל המרחב.
  • המאפיין size מגדיר את המגבלות לגבולות המינימום והמקסימום של 50.
  • הערך של Image מוגדר לגודל 50 על 50, והתוסף size מעביר את הערך הזה.
  • למשתנה wrapContentSize יש מאפיין מיוחד. הוא לוקח ושמה אותו במרכז של הגבולות המינימליים הזמינים. מועבר אליה. הגודל שהוא מעביר להורים שלו שווה את הגבולות המינימליים שהועברו אליו.

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

Image(
    painterResource(R.drawable.hero),
    contentDescription = null,
    Modifier
        .clip(CircleShape)
        .padding(10.dp)
        .size(100.dp)
)

קטע הקוד הזה יפיק את הפלט הבא:

  • המשתנה clip לא משנה את האילוצים.
    • המאפיין padding מקטין את האילוצים המקסימליים.
    • המשתנה המשנה size מגדיר את כל האילוצים ל-100dp.
    • השדה Image פועל בהתאם למגבלות האלה ומדווח בגודל של 100 עד 100dp.
    • המאפיין המשנה padding מוסיף 10dp לכל הגדלים, כך שהוא מגדיל את הרוחב והגובה שמדווחים ב-20dp.
    • בשלב השרטוט, הצירוף clip פועל על קנבס של 120 מאת 120dp. לכן, היא יוצרת מסכה של עיגול בגודל הזה.
    • לאחר מכן, המגביל padding מטמיע את התוכן שלו ב-10dp לכל הגדלים, כך מקטין את גודל הקנבס ל-100 ב-100dp.
    • ה-Image מצויר בלוח הציור הזה. התמונה נחתכת על סמך העיגול המקורי של 120dp, כך שהפלט הוא תוצאה לא עגולה.