מגבילי התאמה מאפשרים לכם לקשט או לשפר תוכן קומפוזבילי. מגבילי התאמה מאפשרים לך דברים כאלה:
- שינוי הגודל, הפריסה, ההתנהגות והמראה של התוכן הקומפוזבילי
- הוספת מידע, כמו תוויות נגישות
- עיבוד קלט של משתמשים
- להוסיף אינטראקציות ברמה גבוהה, כמו יצירה של אלמנט שניתן ללחוץ עליו, מאפשר גלילה ניתן לגרירה או לשינוי מרחק התצוגה
מגבילי התאמה הם אובייקטים רגילים של 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
הופך את המילוי הקומפוזבילי לרוחב המקסימלי שניתן לו ההורה שלו.
מומלץ שכל התכנים הקומפוזביליים יקבלו את הערך modifier
ומעבירים את הערך הזה לצאצא הראשון שפולט ממשק משתמש.
הפעולה הזו הופכת את
את הקוד לשימוש רב יותר, והופך את ההתנהגות שלו לצפויה ואינטואיטיבית יותר. עבור
למידע נוסף, ראו את ההנחיות ל-Compose API, הרכיבים מקבלים ומכבדים
פרמטר הצירוף.
סדר ההתאמות חשוב
הסדר של פונקציות הצירוף הוא משמעותי. מכיוון שכל פונקציה מבצעת שינויים ב-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 Compose יש רשימה של מודיפיקרים מובנים שיעזרו לכם לקשט או להוסיף רכיבים ל-composable. ריכזנו כאן כמה משתני אופן פעולה נפוצים שיעזרו לכם לשנות את הפריסות.
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
(ב-Compose יש גם את המשתנים 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.
כדי לקבל מידע מעמיק יותר על המקרים שבהם כדאי להשתמש בכל אחת מהאפשרויות האלה ואיך לבצע אופטימיזציה
לביצועים, לקרוא
ביצועי כתיבה – דחיית הקריאה כמה שיותר זמן.
היקף הבטיחות של הכתיבה
בקטע 'כתיבה' יש מגבילי התאמה שאפשר להשתמש בהם רק כשמחילים אותם על ילדים של תכנים קומפוזביליים מסוימים. אוכפים את זה באמצעות היקפים מותאמים אישית.
לדוגמה, אם רוצים להגדיל רכיב צאצא לגודל של הרכיב ההורה 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
כמו שראית בסעיף הקודם על ריפוד
size, כברירת מחדל, גודל קומפוזבילי מוגדר על ידי
את התוכן שעוטף. אפשר להגדיר גודל קומפוזבילי שיהיה גמיש במסגרת
משתמש בתכונת הצירוף 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) ) { /*...*/ } } }
חילוץ של משתני אופן פעולה ושימוש חוזר בהם
אפשר לחבר כמה צירופים כדי לקשט או
להרחיב תוכן קומפוזבילי. השרשרת הזו נוצרת באמצעות הממשק Modifier
, שמייצג רשימה מסודרת ואי אפשר לשנות אותה של Modifier.Elements
יחיד.
כל Modifier.Element
מייצג התנהגות אישית, כמו פריסה ושרטוט
וההתנהגויות הגרפיות, כל ההתנהגויות שקשורות לתנועה, להתמקדות וסמנטיקה,
וגם אירועי קלט במכשיר. הסדר שלהם חשוב: רכיבי התאמה
שנוספו תחילה יחולו קודם.
לפעמים כדאי לעשות שימוש חוזר באותם אירועים של שרשרת המשתנים במודולים מרובים, על ידי חילוץ שלהם למשתנים והעברה שלהם להיקפים גבוהים יותר. יש כמה סיבות לכך:
- הקצאת המשתנים לא תתבצע מחדש כשיתבצע עיבוד מחדש של רכיבים מורכבים שמשתמשים בהם
- שרשורי המשתנים יכולים להיות ארוכים ומורכבים מאוד, ולכן שימוש חוזר באותה מכונה של שרשרת יכול להפחית את עומס העבודה שסביבת זמן הריצה של Compose צריכה לבצע כשמשווים ביניהם
- החילוץ הזה עוזר לשפר את הניקיון, העקביות והתחזוקה של הקוד ב-codebase
שיטות מומלצות לשימוש חוזר בהתאמות
אפשר ליצור רשתות 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 ) }
במקום זאת, אפשר ליצור, לחלץ ולהשתמש שוב באותו מופע של המשתנה המשנה ולהעביר אותו ל-composable כך:
// 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 // ... ) // ... }
צריך להעביר את המשתנים המשתנים ברמת ההיקף שחולצו רק לצאצאים הישירים באותו היקף. בקטע Scope safety in Compose מוסבר למה זה חשוב:
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)
רק חשוב לזכור שסדר המשנים חשוב!
מידע נוסף
אנחנו מספקים רשימה מלאה של מגבילי התאמה, עם את הפרמטרים וההיקפים שלהם.
כדי לתרגל את השימוש במטמיעים, אפשר גם לעיין בcodelab בנושא פריסות בסיסיות ב-Compose או להיעזר במאגר Now in Android.
למידע נוסף על משתני אופן התצוגה בהתאמה אישית ועל האופן שבו יוצרים אותם, תוכלו לעיין במאמר פריסות בהתאמה אישית – שימוש במשתנה אופן התצוגה.
מומלץ עבורך
- הערה: טקסט הקישור מוצג כש-JavaScript מושבת
- יסודות של יצירת פריסה
- פעולות של עורך {:#editor-actions}
- פריסות בהתאמה אישית {:#custom-layouts }