ב-Compose, אפשר לשרשר כמה מגדירי שינוי כדי לשנות את המראה והתחושה של רכיב ה-composable. שרשראות של משתני ה-modifier האלה יכולות להשפיע על האילוצים שמועברים לפונקציות ה-composable, שמגדירות את גבולות הרוחב והגובה.
בדף הזה מוסבר איך משתני ה-modifier המשורשרים משפיעים על האילוצים, וכתוצאה מכך על המדידה והמיקום של רכיבי ה-composable.
מגדירי שינוי בעץ ממשק המשתמש
כדי להבין איך משתני ה-modifier משפיעים זה על זה, כדאי לדמיין איך הם מופיעים בעץ ממשק המשתמש, שנוצר במהלך שלב הקומפוזיציה. מידע נוסף מופיע בקטע הרכב.
בעץ של ממשק המשתמש, אפשר להציג את המשנים כצומתי wrapper של צומתי הפריסה:
הוספה של יותר ממאפיין אחד לרכיב Composable יוצרת שרשרת של מאפיינים. כשמשרשרים כמה משתני עיצוב, כל צומת של משתנה עיצוב עוטף את שאר השרשרת ואת צומת הפריסה שבתוכה. לדוגמה, כשמשרשרים את המשנים clip ו-size, צומת המשנה clip עוטף את צומת המשנה size, שעוטף את צומת הפריסה Image.
בשלב הפריסה, האלגוריתם שעובר על העץ נשאר זהה, אבל גם כל צומת של משתנה מקבל ביקור. כך, משתנה יכול לשנות את דרישות הגודל והמיקום של המשתנה או של צומת הפריסה שהוא עוטף.
כפי שמוצג באיור 2, ההטמעה של הרכיבים הקומפוזביליים Image ו-Text עצמם מורכבת משרשרת של משתני שינוי שעוטפים צומת פריסה אחד.
ההטמעות של Row ו-Column הן צומתי פריסה שמתארים איך לפרוס את הצאצאים שלהם.
לסיכום:
- משתני ה-modifier עוטפים משתנה modifier או צומת פריסה יחיד.
- צומתי פריסה יכולים לפרוס כמה צומתי צאצא.
בקטעים הבאים מוסבר איך להשתמש במודל המנטלי הזה כדי להבין את שרשור השינויים ואיך הוא משפיע על הגודל של רכיבי ה-Composable.
אילוצים בשלב הפריסה
שלב הפריסה פועל לפי אלגוריתם של שלושה שלבים כדי למצוא את הרוחב, הגובה והקואורדינטות x ו-y של כל צומת פריסה:
- מדידת צאצאים: צומת מודד את הצאצאים שלו, אם יש כאלה.
- החלטה על גודל משלו: על סמך המדידות האלה, הצומת מחליט על הגודל שלו.
- מיקום צאצאים: כל צומת צאצא ממוקם ביחס למיקום של הצומת עצמו.
Constraints עוזרים למצוא את הגדלים המתאימים לצמתים במהלך שני השלבים הראשונים של האלגוריתם. האילוצים מגדירים את הגבולות המינימליים והמקסימליים של הרוחב והגובה של הצומת. כשהצומת מחליט על הגודל שלו, הגודל שנמדד צריך להיות בטווח הגדלים הזה.
סוגי המגבלות
אילוץ יכול להיות אחד מהבאים:
- תחום: לצומת יש רוחב וגובה מקסימליים ומינימליים.
- ללא גבולות: הצומת לא מוגבל לגודל מסוים. גבולות הרוחב והגובה המקסימליים מוגדרים כאינסוף.
- מדויק: הצומת צריך לעמוד בדרישת גודל מדויקת. הגבולות המינימליים והמקסימליים מוגדרים לאותו ערך.
- שילוב: הצומת פועל לפי שילוב של סוגי האילוצים הקודמים. לדוגמה, אילוץ יכול להגביל את הרוחב ולאפשר גובה מקסימלי בלתי מוגבל, או להגדיר רוחב מדויק אבל לספק גובה מוגבל.
בקטע הבא מוסבר איך האילוצים האלה עוברים מהורה לצאצא.
איך אילוצים עוברים בירושה מהורה לצאצא
בשלב הראשון של האלגוריתם שמתואר בקטע אילוצים בשלב הפריסה, האילוצים מועברים מההורה לצאצא בעץ ממשק המשתמש.
כשהצומת הראשי מודד את הצאצאים שלו, הוא מספק את האילוצים האלה לכל צאצא כדי להודיע להם מה הגודל המותר שלהם. לאחר מכן, כשהוא קובע את הגודל שלו, הוא גם פועל לפי האילוצים שהועברו על ידי ההורים שלו.
ברמה הכללית, האלגוריתם פועל באופן הבא:
- כדי להחליט מה הגודל שהוא רוצה לתפוס בפועל, צומת הבסיס בעץ ממשק המשתמש מודד את הצאצאים שלו ומעביר את אותן מגבלות לצאצא הראשון שלו.
- אם הצאצא הוא משתנה שלא משפיע על המדידה, הוא מעביר את האילוצים למשתנה הבא. האילוצים מועברים בשרשרת של משני העיצוב כמו שהם, אלא אם מגיעים למשנה עיצוב שמשפיע על המדידה. האילוצים משנים את הגודל שלהם בהתאם.
- כשמגיעים לצומת שאין לו צאצאים (שנקרא "צומת עלה"), הוא מחליט על הגודל שלו על סמך האילוצים שהועברו, ומחזיר את הגודל הזה לצומת ההורה שלו.
- ההורה מתאים את האילוצים שלו על סמך המידות של הצאצא הזה, וקורא לצאצא הבא עם האילוצים המותאמים האלה.
- אחרי שכל הצאצאים של צומת הורה נמדדים, צומת ההורה מחליט על הגודל שלו ומעביר את המידע הזה לצומת ההורה שלו.
- כך, כל העץ נסרק קודם כל לעומק. בסופו של דבר, כל הצמתים קובעים את הגדלים שלהם, ושלב המדידה מסתיים.
לדוגמה מפורטת, צפו בסרטון Constraints and modifier order.
מגבילים שמשפיעים על אילוצים
בקטע הקודם למדתם שחלק מהתכונות יכולות להשפיע על גודל האילוץ. בקטעים הבאים מתוארים משתנים ספציפיים שמשפיעים על האילוצים.
המשתנה size
המשתנה size מגדיר את הגודל המועדף של התוכן.
לדוגמה, עץ ממשק המשתמש הבא צריך לעבור רינדור בקונטיינר בגודל 300dp על 200dp. האילוצים מוגבלים, ומאפשרים רוחב בין 100dp ל-300dp וגובה בין 100dp ל-200dp:
המשתנה size מתאים את האילוצים הנכנסים לערך שמועבר אליו.
בדוגמה הזו, הערך הוא 150dp:
size משנה את האילוצים ל-150dp.אם הרוחב והגובה קטנים מהגבול המינימלי של האילוץ, או גדולים מהגבול המקסימלי של האילוץ, ה-modifier יתאים לאילוצים שהועברו בצורה הכי קרובה שאפשר, תוך שמירה על האילוצים שהועברו:
size שמתאים לאילוץ שהועבר בצורה הכי קרובה שאפשר.חשוב לזכור שאי אפשר לשרשר כמה משתני size. המשתנה הראשון size מגדיר גם את האילוץ המינימלי וגם את האילוץ המקסימלי לערך קבוע. גם אם משתמשים ב-modifier השני כדי לבקש גודל קטן או גדול יותר, הוא עדיין צריך לעמוד בגבולות המדויקים שהועברו, כך שהוא לא יבטל את הערכים האלה:
size, שבה הערך השני שמועבר (50dp) לא מבטל את הערך הראשון (100dp).המשתנה requiredSize
אם אתם רוצים שהצומת יבטל את האילוצים הנכנסים, השתמשו במשתנה requiredSize במקום size. המשתנה requiredSize מחליף את האילוצים הנכנסים ומעביר את הגודל שציינתם כגבולות מדויקים.
כשהגודל מועבר חזרה במעלה העץ, צומת הצאצא ימוקם במרכז המרחב הזמין:
requiredSize מבטל את האילוצים הנכנסים מהמשתנה size.המשתנים width ו-height
המשתנה size מתאים גם את הרוחב וגם את הגובה של האילוצים. באמצעות המשתנה width, אפשר להגדיר רוחב קבוע אבל להשאיר את הגובה לא מוגדר.
באופן דומה, בעזרת המשתנה height אפשר להגדיר גובה קבוע, אבל להשאיר את הרוחב לא מוגדר:
width והמשתנה height מגדירים רוחב וגובה קבועים, בהתאמה.המשתנה sizeIn
המשתנה sizeIn מאפשר להגדיר אילוצים מדויקים של מינימום ומקסימום לרוחב ולגובה. אם אתם צריכים שליטה מדויקת על האילוצים, השתמשו במשתנה sizeIn.
sizeIn עם ההגדרות minWidth, maxWidth, minHeight ו-maxHeight.דוגמאות
בקטע הזה מוצג ומוסבר הפלט של כמה קטעי קוד עם משתני שינוי משורשרים.
Image( painterResource(R.drawable.hero), contentDescription = null, Modifier .fillMaxSize() .size(50.dp) )
הפלט של קטע הקוד הזה הוא:
Image ממלא את הגודל המקסימלי כתוצאה משרשרת המשתנים.- המשתנה
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) )
הפלט של קטע הקוד הזה הוא:
Image ממורכז והגודל שלו הוא 50dp.- המשתנה
fillMaxSizeמתאים את האילוצים כדי להגדיר את הרוחב והגובה המינימליים לערך המקסימלי –300dpברוחב ו-200dpבגובה. - המשתנה
wrapContentSizeמאפס את האילוצים המינימליים. לכן, בעוד ש-fillMaxSizeגרם לאילוצים קבועים,wrapContentSizeמאפס אותו בחזרה לאילוצים מוגבלים. הצומת הבא יכול לתפוס שוב את כל המקום, או להיות קטן יותר מכל המקום. - המשתנה
sizeמגדיר את האילוצים לגבולות המינימום והמקסימום של50. - ה-
Imageמוגדר לגודל של50על50, והמשתנהsizeמעביר את זה. - למשתנה
wrapContentSizeיש מאפיין מיוחד. הוא לוקח את הצאצא שלו וממקם אותו במרכז הגבולות המינימליים הזמינים שהועברו אליו. לכן, הגודל שהוא מעביר להורים שלו שווה לגבולות המינימליים שהועברו אליו.
על ידי שילוב של שלושה משתני שינוי בלבד, אתם יכולים להגדיר גודל לרכיב ה-composable ולמרכז אותו ברכיב ההורה שלו.
Image( painterResource(R.drawable.hero), contentDescription = null, Modifier .clip(CircleShape) .padding(10.dp) .size(100.dp) )
הפלט של קטע הקוד הזה הוא:
- המשתנה
clipלא משנה את האילוצים. - המשתנה
paddingמקטין את האילוצים המקסימליים. - המשתנה
sizeמגדיר את כל האילוצים ל-100dp. - ה-
Imageעומד במגבלות האלה ומדווח על גודל של100dpעל100dp. - המשתנה
paddingמוסיף10dpלכל הצדדים של הגודל שדווח על ידיImage, כך שהפריסה עם המרווח הפנימי מדווחת על רוחב וגובה של120dp. - עכשיו, בשלב הציור, המשתנה
clipפועל על אזור ציור בגודל120dpעל120dp. הוא יוצר מסכה עגולה בגודל הזה. - המשתנה
paddingמוסיף מרווח פנימי של10dpלתוכן מכל הצדדים, וכך מקטין את גודל אזור העריכה שלImageל-100dpעל100dp. - ה-
Imageמשורטט בקנבס הקטן יותר. התמונה נחתכת על סמך העיגול המקורי של120dp, כך שהתוצאה היא לא עגולה.