מודификаторים מאפשרים לקשט או להוסיף רכיבים ל-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 accept and respect a Modifier parameter.
סדר המשתנים המשתנים חשוב
הסדר של פונקציות המשתנה המשנה הוא משמעותי. מכיוון שכל פונקציה מבצעת שינויים ב-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.
מידע מפורט יותר על הזמנים שבהם כדאי להשתמש בכל אחת מהאפשרויות האלה ועל אופן האופטימיזציה לביצועים מפורט בקטע ביצועי הרכבת קובץ – דחיית קריאות למשך זמן רב ככל האפשר.
אבטחת היקף ב-Compose
ב-Compose יש משתני אופן (modifiers) שאפשר להשתמש בהם רק כשהם חלים על צאצאים של רכיבים מסוימים ליצירה. Compose אוכף את הכלל הזה באמצעות היקפים מותאמים אישית.
לדוגמה, אם רוצים להגדיל רכיב צאצא לגודל של הרכיב ההורה 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 ) }
במקום זאת, אפשר ליצור, לחלץ ולהשתמש שוב באותו מופע של המשתנה המשנה ולהעביר אותו ל-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 ספציפי. במקרה של משתני מודיפיקטור ללא היקף, אפשר לחלץ אותם בקלות מחוץ לרכיבי ה-Composables כמשתנים פשוטים:
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 }