מודификаторים מאפשרים לקשט או להוסיף רכיבים ל-composable. מגבילי התאמה מאפשרים לכם לבצע את הפעולות הבאות:
- שינוי הגודל, הפריסה, ההתנהגות והמראה של התוכן הקומפוזבילי
- הוספת מידע, כמו תוויות נגישות
- עיבוד קלט של משתמשים
- הוספת אינטראקציות ברמה גבוהה, כמו הפיכת אלמנט לקליקבילי, לגלילה, לגרירה או להגדלת התצוגה שלו
משתני פונקציה הם אובייקטים רגילים של Kotlin. כדי ליצור פונקציית שינוי, קוראים לאחת מפונקציות הכיתה Modifier
:
@Composable private fun Greeting(name: String) { Column(modifier = Modifier.padding(24.dp)) { Text(text = "Hello,") Text(text = name) } }
אפשר לשרשר את הפונקציות האלה כדי ליצור מהן קומפוזיציה:
@Composable private fun Greeting(name: String) { Column( modifier = Modifier .padding(24.dp) .fillMaxWidth() ) { Text(text = "Hello,") Text(text = name) } }
בקוד שלמעלה, שימו לב לפונקציות צירוף שונות שנעשה בהן שימוש יחד.
padding
תופסת רווח מסביב לרכיב.fillMaxWidth
גורם לרכיב ה-Composable למלא את הרוחב המקסימלי שהוגדר לו על ידי ההורה שלו.
השיטה המומלצת היא שכל התכנים הקומפוזביליים יקבלו את הפרמטר modifier
, ויעבירו את הצירוף הזה לתת-הצאצא הראשון שלו שפולט ממשק משתמש.
כך תוכלו לעשות שימוש חוזר בקוד בקלות רבה יותר, וההתנהגות שלו תהיה צפויה ואינטואיטיבית יותר. מידע נוסף זמין בהנחיות של Compose API במאמר Elements מקבלים ומכבדים פרמטר Modifier.
סדר המשתנים המשתנים חשוב
הסדר של פונקציות המשתנה המשנה הוא משמעותי. מכיוון שכל פונקציה מבצעת שינויים ב-Modifier
שהפונקציה הקודמת החזירה, הסדר משפיע על התוצאה הסופית. בואו נראה דוגמה לכך:
@Composable fun ArtistCard(/*...*/) { val padding = 16.dp Column( Modifier .clickable(onClick = onClick) .padding(padding) .fillMaxWidth() ) { // rest of the implementation } }
בקוד שמעל כל האזור ניתן ללחוץ על, כולל המרווח הפנימי שמסביב, כי מקש הצירוף padding
הוחל אחרי המגביל clickable
. אם מגדירים את סדר המשתנים המשתנים הפוך, המרחב המשותף שנוסף באמצעות padding
לא מגיב לקלט של המשתמש:
@Composable fun ArtistCard(/*...*/) { val padding = 16.dp Column( Modifier .padding(padding) .clickable(onClick = onClick) .fillMaxWidth() ) { // rest of the implementation } }
גורמי שינוי מובנים
ב-Jetpack פיתוח נייטיב יש רשימה של רכיבי שינוי מובנים שיעזרו לכם לקשט או לשפר תוכן קומפוזבילי. ריכזנו כאן כמה משתני אופן פעולה נפוצים שיעזרו לכם לשנות את הפריסות.
padding
וגם size
כברירת מחדל, פריסות שסופקו ב-Compose עוטפות את הצאצאים שלהן. אבל אפשר להגדיר את הגודל באמצעות מקש הצירוף size
:
@Composable fun ArtistCard(/*...*/) { Row( modifier = Modifier.size(width = 400.dp, height = 100.dp) ) { Image(/*...*/) Column { /*...*/ } } }
שימו לב: יכול להיות שהגודל שציינתם לא יתקבל אם הוא לא עומד באילוצים שמגיעים מהרכיב ההורה של הפריסה. אם אתם רוצים שהגודל של הרכיב הניתן ליצירה יהיה קבוע ללא קשר למגבלות הנכנסות, צריך להשתמש במערך requiredSize
:
@Composable fun ArtistCard(/*...*/) { Row( modifier = Modifier.size(width = 400.dp, height = 100.dp) ) { Image( /*...*/ modifier = Modifier.requiredSize(150.dp) ) Column { /*...*/ } } }
בדוגמה הזו, גם אם ההורה height
מוגדר כ-100.dp
, הגובה של Image
יהיה 150.dp
, כי המשתנה המשנה requiredSize
מקבל עדיפות.
אם רוצים שפריסת צאצא תמלא את כל הגובה הזמין שמותר על ידי ההורה, מוסיפים את מקש הצירוף fillMaxHeight
(כתיבה כוללת גם את fillMaxSize
ואת fillMaxWidth
):
@Composable fun ArtistCard(/*...*/) { Row( modifier = Modifier.size(width = 400.dp, height = 100.dp) ) { Image( /*...*/ modifier = Modifier.fillMaxHeight() ) Column { /*...*/ } } }
כדי להוסיף ריפוד מסביב לאלמנט, מגדירים את המאפיין padding
.
אם רוצים להוסיף רווח מעל קו הטקסט כך שיהיה מרחק ספציפי בין החלק העליון של הפריסה לקו הטקסט, משתמשים במשתנה paddingFromBaseline
:
@Composable fun ArtistCard(artist: Artist) { Row(/*...*/) { Column { Text( text = artist.name, modifier = Modifier.paddingFromBaseline(top = 50.dp) ) Text(artist.lastSeenOnline) } } }
היסט
כדי למקם פריסה ביחס למיקום המקורי שלה, מוסיפים את המשתנה offset
ומגדירים את ההיסט בצייר x ו-y.
התנודות יכולות להיות חיוביות וגם שליליות. ההבדל בין padding
לבין offset
הוא שהוספת offset
ל-composable לא משנה את המדידות שלו:
@Composable fun ArtistCard(artist: Artist) { Row(/*...*/) { Column { Text(artist.name) Text( text = artist.lastSeenOnline, modifier = Modifier.offset(x = 4.dp) ) } } }
המשתנה offset
מיושם אופקית בהתאם לכיוון הפריסה.
בהקשר של שמאל לימין, ערך חיובי של offset
מעביר את הרכיב ימינה, ואילו בהקשר של ימין לשמאל, הוא מעביר את הרכיב שמאלה.
אם צריך להגדיר היסט בלי להביא בחשבון את כיוון הפריסה, כדאי לעיין במשתנה absoluteOffset
, שבו ערך היסט חיובי תמיד מעביר את הרכיב ימינה.
המשתנה המשנה offset
מספק שתי עומסי יתר – offset
שמקבל את הזזות האופק כפרמטרים ו-offset
שמקבל פונקציית lambda.
למידע מפורט יותר מתי כדאי להשתמש בכל אחת מהאפשרויות האלה ואיך לבצע אופטימיזציה לביצועים, קראו את הקטע כתיבת ביצועים – דחיית קריאה ככל האפשר.
היקף הבטיחות של הכתיבה
ב-Compose יש משתני אופן (modifiers) שאפשר להשתמש בהם רק כשהם חלים על צאצאים של רכיבים מסוימים ליצירה. אוכפים את זה באמצעות היקפים מותאמים אישית.
לדוגמה, אם רוצים להגדיל רכיב צאצא לגודל של הרכיב ההורה Box
בלי להשפיע על הגודל של Box
, משתמשים במודификатор matchParentSize
. matchParentSize
זמין רק ב-BoxScope
.
לכן, אפשר להשתמש בו רק בנכס צאצא בתוך נכס הורה מסוג Box
.
בזכות הבטיחות ברמת ההיקף, לא תוכלו להוסיף משתני אופן פעולה שלא יפעלו ברכיבים אחרים ובהיקפים אחרים, וכך לחסוך זמן בניסיון וטעייה.
התאמות בהיקף שהוגדר מיידעות את ההורה לגבי מידע מסוים שההורים צריכים לדעת על הילד או הילדה. הם נקראים גם התאמות של נתוני הורה. המאפיינים הפנימיים שלהם שונים מאלה של המשתנים למטרות כלליות, אבל מבחינת השימוש, ההבדלים האלה לא חשובים.
matchParentSize
בעוד Box
כפי שצוין למעלה, אם רוצים שהפריסה של הצאצא תהיה באותו גודל כמו הפריסה של ההורה Box
בלי להשפיע על הגודל של Box
, צריך להשתמש במשתנה המשנה matchParentSize
.
הערה: המאפיין matchParentSize
זמין רק בהיקף Box
, כלומר הוא חל רק על צאצאים ישירים של רכיבים מורכבים מסוג Box
.
בדוגמה הבאה, הצאצא Spacer
מקבל את הגודל שלו מיחידת ההורה Box
, שבתוכה הוא מקבל את הגודל שלו מהילדים הגדולים ביותר,
ArtistCard
במקרה הזה.
@Composable fun MatchParentSizeComposable() { Box { Spacer( Modifier .matchParentSize() .background(Color.LightGray) ) ArtistCard() } }
אם נעשה שימוש ב-fillMaxSize
במקום ב-matchParentSize
, הפרמטר Spacer
יתייחס לכל נפח האחסון הזמין שמותר להורה, וכך ההורה יתרחב ותמלא את כל השטח הזמין.
weight
ב-Row
וב-Column
כפי שראיתם בקטע הקודם בנושא הגדרת שוליים וגודל, כברירת מחדל, הגודל של רכיב שאפשר ליצור ממנו קומפוזיציה מוגדר לפי התוכן שהוא עוטף. אפשר להגדיר גודל קומפוזבילי שיהיה גמיש בתוך ההורה שלו באמצעות המגביל weight
שזמין רק ב-RowScope
וב-ColumnScope
.
ניקח Row
שמכיל שני רכיבים של Box
.
התיבה הראשונה מקבלת ערך של פי שניים מ-weight
של התיבה השנייה, כך שהיא מקבלת פי שניים ברוחב. מכיוון ש-Row
הוא 210.dp
רחב, ה-Box
הראשון הוא 140.dp
רחב והשני הוא 70.dp
:
@Composable fun ArtistCard(/*...*/) { Row( modifier = Modifier.fillMaxWidth() ) { Image( /*...*/ modifier = Modifier.weight(2f) ) Column( modifier = Modifier.weight(1f) ) { /*...*/ } } }
חילוץ של משתני אופן פעולה ושימוש חוזר בהם
אפשר לשרשר יחד כמה משתני אופן כדי לקשט או להוסיף לרכיב ה-Composable. השרשרת הזו נוצרת באמצעות הממשק Modifier
, שמייצג רשימה מסודרת ואי אפשר לשנות אותה של Modifier.Elements
יחיד.
כל Modifier.Element
מייצג התנהגות ספציפית, כמו התנהגות של פריסה, ציור וגרפיקה, כל ההתנהגויות שקשורות לתנועות, ל-focus ולסמנטיקה, וגם אירועי קלט של המכשיר. הסדר שלהם חשוב: רכיבי הצירוף שמתווספים ראשונים יחולו ראשונים.
לפעמים כדאי לעשות שימוש חוזר באותן מופע של שרשרת המשתנים במודולים מרובים, על ידי חילוץ שלהם למשתנים והעברה שלהם להיקפים גבוהים יותר. יש כמה סיבות לכך:
- הקצאת המשתנים לא תתבצע מחדש כשיתבצע עיבוד מחדש של רכיבים מורכבים שמשתמשים בהם
- שרשורי המשתנים יכולים להיות ארוכים ומורכבים מאוד, ולכן שימוש חוזר באותה מכונה של שרשרת יכול להפחית את עומס העבודה שסביבת זמן הריצה של Compose צריכה לבצע כשמשווים ביניהם
- החילוץ הזה מעודד ניקיון, עקביות ותחזוקה של הקוד בבסיס הקוד
שיטות מומלצות לשימוש חוזר במודיפיקורים
אתם יכולים ליצור רשתות Modifier
משלכם ולחלץ אותן כדי לעשות בהן שימוש חוזר במספר רכיבים שאפשר לשלב. אפשר פשוט לשמור את המשתנה המשנה, כי הוא אובייקט שדומה לנתונים:
val reusableModifier = Modifier .fillMaxWidth() .background(Color.Red) .padding(12.dp)
חילוץ ושימוש חוזר של מגבילים במהלך צפייה במצב שמשתנה לעיתים קרובות
כשמשתמשים ברכיבים מורכבים שמשתנים בתדירות גבוהה, כמו מצבי אנימציה או scrollState
, יכול להיות שיתבצעו מספר רב של קומפוזיציות מחדש. במקרה כזה, המשנים יוקצו לכל הרכבה מחדש, ויכול להיות שגם לכל פריים:
@Composable fun LoadingWheelAnimation() { val animatedState = animateFloatAsState(/*...*/) LoadingWheel( // Creation and allocation of this modifier will happen on every frame of the animation! modifier = Modifier .padding(12.dp) .background(Color.Gray), animatedState = animatedState ) }
במקום זאת, אפשר ליצור את אותו מופע של הצירוף, לחלץ אותו ולהשתמש בו שוב, ולהעביר אותו לתוכן הקומפוזבילי, באופן הבא:
// Now, the allocation of the modifier happens here: val reusableModifier = Modifier .padding(12.dp) .background(Color.Gray) @Composable fun LoadingWheelAnimation() { val animatedState = animateFloatAsState(/*...*/) LoadingWheel( // No allocation, as we're just reusing the same instance modifier = reusableModifier, animatedState = animatedState ) }
חילוץ של משתני אופן פעולה ללא היקף ושימוש חוזר בהם
אפשר לבטל את ההיקף של המשתנים המשתנים או להגדיר את ההיקף שלהם ל-composable ספציפי. במקרה של משתני מודיפיקטור ללא היקף, אפשר לחלץ אותם בקלות מחוץ לרכיבים הניתנים לשילוב כמשתנים פשוטים:
val reusableModifier = Modifier .fillMaxWidth() .background(Color.Red) .padding(12.dp) @Composable fun AuthorField() { HeaderText( // ... modifier = reusableModifier ) SubtitleText( // ... modifier = reusableModifier ) }
האפשרות הזו יכולה להיות שימושית במיוחד בשילוב עם פריסות 'איטז'. ברוב המקרים, כדאי להגדיר את אותם המשתנים לכל כמות הפריטים, שעשויה להיות משמעותית:
val reusableItemModifier = Modifier .padding(bottom = 12.dp) .size(216.dp) .clip(CircleShape) @Composable private fun AuthorList(authors: List<Author>) { LazyColumn { items(authors) { AsyncImage( // ... modifier = reusableItemModifier, ) } } }
חילוץ של מגבילי היקף ושימוש חוזר בהם
כשעובדים עם מודיפיקרים שמוגדרים לרכיבים מורכבים מסוימים, אפשר לחלץ אותם לרמה הגבוהה ביותר האפשרית ולהשתמש בהם מחדש במקרים המתאימים:
Column(/*...*/) { val reusableItemModifier = Modifier .padding(bottom = 12.dp) // Align Modifier.Element requires a ColumnScope .align(Alignment.CenterHorizontally) .weight(1f) Text1( modifier = reusableItemModifier, // ... ) Text2( modifier = reusableItemModifier // ... ) // ... }
צריך להעביר את המשתנים המשתנים ברמת ההיקף שחולצו רק לצאצאים הישירים באותו היקף. למידע נוסף על החשיבות של המדיניות הזו, אפשר לעיין בסעיף בטיחות היקף בכתיבה:
Column(modifier = Modifier.fillMaxWidth()) { // Weight modifier is scoped to the Column composable val reusableItemModifier = Modifier.weight(1f) // Weight will be properly assigned here since this Text is a direct child of Column Text1( modifier = reusableItemModifier // ... ) Box { Text2( // Weight won't do anything here since the Text composable is not a direct child of Column modifier = reusableItemModifier // ... ) } }
שרשור נוסף של המשתנים שחולצו
אפשר לשרשר או לצרף עוד שרשראות שחולצו באמצעות קריאה לפונקציה .then()
:
val reusableModifier = Modifier .fillMaxWidth() .background(Color.Red) .padding(12.dp) // Append to your reusableModifier reusableModifier.clickable { /*...*/ } // Append your reusableModifier otherModifier.then(reusableModifier)
חשוב לזכור שסדר המשתנים המשתנים חשוב!
מידע נוסף
אנחנו מספקים רשימה מלאה של המשתנים המשתנים, עם הפרמטרים וההיקפים שלהם.
כדי לתרגל את השימוש במטמיעים, אפשר גם לעבור על הקודלאב בנושא פריסות בסיסיות ב-Compose או לעיין במאגר Now in Android.
למידע נוסף על משתני אופן התצוגה בהתאמה אישית ועל האופן שבו יוצרים אותם, אפשר לעיין במאמר פריסות בהתאמה אישית – שימוש במשתנה אופן התצוגה.
מומלץ עבורך
- הערה: טקסט הקישור מוצג כש-JavaScript מושבת
- יסודות של יצירת פריסה
- פעולות של עורך {:#editor-actions}
- פריסות בהתאמה אישית {:#custom-layouts }