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

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

לסיכום:
- המאפיין modifiers עוטף צומת יחיד של modifier או layout.
- צמתי פריסה יכולים לפרוס כמה צמתי צאצא.
בקטעים הבאים מוסבר איך להשתמש במודל המנטלי הזה כדי להבין את שרשור שינויי המאפיינים ואת ההשפעה שלו על הגודל של רכיבי ה-Composable.
אילוצים בשלב הפריסה
בשלב הפריסה פועל אלגוריתם בן שלושה שלבים כדי למצוא את הרוחב, הגובה וקואורדינטות ה-x וה-y של כל צומת פריסה:
- מדידת ילדים: צומת מודד את הצמתים המשניים שלו, אם יש כאלה.
- קביעת גודל עצמאי: על סמך המידות האלה, הצומת קובע את הגודל שלו.
- מיקום ילדים: כל צומת צאצא ממוקם ביחס למיקום של הצומת עצמו.
Constraints
כדי לעזור למצוא את הגדלים הנכונים של הצמתים במהלך שני השלבים הראשונים של האלגוריתם. אילוצים מגדירים את הגבולות המינימליים והמקסימליים של הרוחב והגובה של צומת. כשצומת מחליט על הגודל שלו, הגודל הנמדד שלו צריך להיות בטווח הגדלים הזה.
סוגים של אילוצים
אילוצים יכולים להיות אחד מהסוגים הבאים:
- מוגבל: ל-node יש רוחב וגובה מקסימליים ומינימליים.

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

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

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

בקטע הבא מוסבר איך ההגבלות האלה מועברות מהורה לילד.
איך אילוצים מועברים מרכיב ראשי לרכיב משני
במהלך השלב הראשון של האלגוריתם שמתואר בקטע Constraints in the layout phase, ההגבלות מועברות מהרכיב העליון לרכיב הצאצא בעץ ממשק המשתמש.
כשצומת אב מודד את צאצאיו, הוא מספק את האילוצים האלה לכל צאצא כדי להודיע לו מה הגודל המקסימלי או המינימלי שלו. לאחר מכן, כשהוא מחליט על הגודל שלו, הוא פועל בהתאם למגבלות שהועברו אליו על ידי רכיבי האב שלו.
באופן כללי, האלגוריתם פועל כך:
- כדי להחליט על הגודל שהוא רוצה לתפוס, צומת הבסיס בעץ ממשק המשתמש מודד את הצמתים הצאצאים שלו ומעביר את אותן אילוצים לצומת הצאצא הראשון שלו.
- אם רכיב ה-child הוא משנה שלא משפיע על המדידה, הוא מעביר את האילוצים למשנה הבא. האילוצים מועברים בשרשרת של שינויי ההגדרות כמו שהם, אלא אם מגיעים לשינוי הגדרה שמשפיע על המדידה. לאחר מכן, הגודל של האילוצים משתנה בהתאם.
- אחרי שמגיעים לצומת שאין לו צאצאים (שנקרא 'צומת עלה'), הוא מחליט על הגודל שלו על סמך האילוצים שהועברו אליו, ומחזיר את הגודל הזה אחרי הפתרון לצומת ההורה שלו.
- האלמנט ההורה מתאים את המגבלות שלו על סמך המידות של אלמנט הצאצא, וקורא לאלמנט הצאצא הבא עם המגבלות המותאמות האלה.
- אחרי שמודדים את כל הילדים של ההורה, צומת ההורה מחליט על הגודל שלו ומודיע על כך להורה שלו.
- כך מתבצעת סריקה של כל העץ לעומק. בסופו של דבר, כל הצמתים מחליטים על הגדלים שלהם, ושלב המדידה מסתיים.
דוגמה מפורטת מופיעה בסרטון Constraints and modifier order (אילוצים וסדר שינויים).
משנים שמשפיעים על אילוצים
בקטע הקודם למדתם שחלק מהמשנים יכולים להשפיע על גודל האילוץ. בקטעים הבאים מתוארים משנים ספציפיים שמשפיעים על אילוצים.
size
modifier
המשנה size
מציין את הגודל המועדף של התוכן.
לדוגמה, עץ ממשק המשתמש הבא צריך להיות מוצג בקונטיינר של 300dp
על 200dp
. האילוצים מוגבלים, כך שהרוחב יכול להיות בין 100dp
ל-300dp
, והגובה יכול להיות בין 100dp
ל-200dp
:

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

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

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

size
, שבה הערך השני שמועבר (50dp
) לא מבטל את הערך הראשון (100dp
).requiredSize
modifier
אם אתם צריכים שהצומת שלכם יבטל את האילוצים הנכנסים, אתם צריכים להשתמש במחרוזת requiredSize
במקום במחרוזת size
. המשנה requiredSize
מחליף את האילוצים הנכנסים ומעביר את הגודל שציינתם כגבולות מדויקים.
כשהגודל מועבר חזרה במעלה העץ, צומת הצאצא ימוקם במרכז של המקום הפנוי:

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

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

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
, כך שהפלט הוא תוצאה לא עגולה.
- המשנה