אמצעי שינוי מאפשרים לכם להוסיף עיצוב או לשפר את הקומפוזיציה. המשנים מאפשרים לכם לבצע פעולות מהסוגים הבאים:
- שינוי הגודל, הפריסה, ההתנהגות והמראה של הרכיב הקומפוזבילי
- הוספת מידע, כמו תוויות נגישות
- עיבוד קלט של משתמשים
- הוספת אינטראקציות ברמה גבוהה, כמו הפיכת אלמנט לקליקבילי, ניתן לגלילה, ניתן לגרירה או ניתן להגדלה
המשנים הם אובייקטים רגילים של 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
ויעבירו את ה-modifier הזה לצאצא הראשון שלהן שיוצר ממשק משתמש.
כך הקוד יהיה ניתן לשימוש חוזר, וההתנהגות שלו תהיה צפויה ואינטואיטיבית יותר. למידע נוסף, אפשר לעיין בהנחיות לשימוש ב-Compose API, רכיבים מקבלים ומכבדים פרמטר 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 Compose מספק רשימה של משני מאפיינים מובנים שיעזרו לכם לעצב או לשפר רכיב שאפשר להרכיב. אלה כמה משנים נפוצים שתשתמשו בהם כדי לשנות את הפריסות.
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 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 שמקבל למדה.
לקבלת מידע מפורט יותר על המקרים שבהם כדאי להשתמש בכל אחת מהאפשרויות האלה ועל אופטימיזציה של הביצועים, כדאי לקרוא את הקטע שיפור הביצועים של כתיבה – דחיית קריאות ככל האפשר.
בטיחות היקף ההרשאות ב-Compose
ב-Compose יש משנים שאפשר להשתמש בהם רק כשמחילים אותם על צאצאים של רכיבי Compose מסוימים. ב-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() } }
אם במקום matchParentSize השתמשו ב-fillMaxSize, הרכיב Spacer יתפוס את כל המקום שזמין לרכיב האב, וכתוצאה מכך רכיב האב יתרחב וימלא את כל המקום שזמין לו.
weight ב-Row ו-Column
כפי שראיתם בקטע הקודם בנושא שוליים פנימיים וגודל, כברירת מחדל, הגודל של רכיב שאפשר להרכיב מוגדר לפי התוכן שהוא מכיל. אפשר להגדיר את הגודל של תוכן קומפוזבילי כך שיהיה גמיש בתוך רכיב האב שלו באמצעות weight Modifier שזמין רק ב-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 מייצג התנהגות ספציפית, כמו התנהגויות שקשורות לפריסה, לציור ולגרפיקה, התנהגויות שקשורות למחוות, התנהגויות שקשורות למיקוד ולסמנטיקה, וגם אירועי קלט במכשיר. סדר הרכיבים חשוב: רכיבי שינוי שנוספו ראשונים יחולו ראשונים.
לפעמים כדאי לעשות שימוש חוזר באותם מופעים של שרשרת משנים בכמה רכיבים קומפוזביליים, על ידי חילוץ שלהם למשתנים והעברה שלהם להיקפים גבוהים יותר. השימוש ב-Lint יכול לשפר את קריאות הקוד או את הביצועים של האפליקציה מכמה סיבות:
- הקצאה מחדש של המאפיינים לא תחזור על עצמה כשמתבצעת רה-קומפוזיציה של רכיבים קומפוזביליים שמשתמשים בהם
- יכול להיות שרצפים של משנים יהיו ארוכים ומורכבים מאוד, ולכן שימוש חוזר באותו מופע של רצף יכול להקל על עומס העבודה שזמן הריצה של 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 ) }
חילוץ של משנים ללא היקף ושימוש חוזר בהם
אפשר להגדיר את המאפיינים המשנים כך שיחולו על כל הקומפוזיציות או רק על קומפוזיציה ספציפית. במקרה של משנים ללא היקף, אפשר לחלץ אותם בקלות מחוץ לרכיבים הניתנים להרכבה כמשתנים פשוטים:
val reusableModifier = Modifier .fillMaxWidth() .background(Color.Red) .padding(12.dp) @Composable fun AuthorField() { HeaderText( // ... modifier = reusableModifier ) SubtitleText( // ... modifier = reusableModifier ) }
האפשרות הזו יכולה להיות שימושית במיוחד בשילוב עם פריסות Lazy. ברוב המקרים, כדאי שכל הפריטים שלכם, שיכולים להיות בכמות גדולה, יכללו את אותם משני מחיר בדיוק:
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 // ... ) // ... }
צריך להעביר רק את שינויי ההיקף שחולצו לצאצאים הישירים באותו היקף. מידע נוסף על החשיבות של הנושא הזה מופיע בקטע היקף הבטיחות ב-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 מושבת
- העקרונות הבסיסיים של פריסת Compose
- פעולות ב-Editor {:#editor-actions}
- פריסות בהתאמה אישית {:#custom-layouts }