עם Jetpack פיתוח נייטיב קל יותר לעצב ולבנות את ממשק המשתמש של האפליקציה. Compose ממיר את המצב לרכיבי ממשק משתמש באמצעות:
- הרכבת רכיבים
- פריסה של רכיבים
- ציור רכיבים
המסמך הזה מתמקד בפריסת הרכיבים השונים, עם הסברים על חלק מאבני הבניין שפלטפורמת 'כתיבה' מספקת כדי לעזור לכם לפרוס את הרכיבים בממשק המשתמש.
מטרות הפריסות ב-Compose
להטמעה של מערכת הפריסה ב-Jetpack Compose יש שתי מטרות עיקריות:
- ביצועים גבוהים
- יכולת לכתוב בקלות פריסות מותאמות אישית
יסודות של פונקציות הניתנות להגדרה
פונקציות הניתנות להגדרה הן אבני הבניין הבסיסיות של Compose. פונקציה שניתנת ליצירה היא פונקציה שמפיקה Unit
שמתארת חלק מממשק המשתמש. הפונקציה מקבלת קלט מסוים ויוצרת את מה שמוצג במסך. למידע נוסף על רכיבים שניתנים לשילוב, אפשר לעיין במסמכי העזרה בנושא המודל הקוגניטיבי של Compose.
פונקציה שניתנת ליצירה יכולה להפיק כמה רכיבי ממשק משתמש. עם זאת, אם לא תספקו הנחיות לגבי סדר הפריטים, יכול להיות שהם ימוקמו ב-Compose באופן שלא יתאים לכם. לדוגמה, הקוד הזה יוצר שני רכיבי טקסט:
@Composable fun ArtistCard() { Text("Alfred Sisley") Text("3 minutes ago") }
בלי הנחיות לגבי אופן הסדר שלהם, רכיבי הטקסט ב-Compose יוערמו זה על גבי זה, כך שלא ניתן יהיה לקרוא אותם:
Compose כולל אוסף של פריסות מוכנות לשימוש שיעזרו לכם לסדר את רכיבי ממשק המשתמש, וגם מאפשר לכם להגדיר בקלות פריסות משלכם שמתמקדות בצרכים ספציפיים.
רכיבי פריסה רגילים
במקרים רבים, אפשר פשוט להשתמש ברכיבי הפריסה הרגילים של Compose.
בעזרת Column
תוכלו למקם פריטים בצורה אנכית על המסך.
@Composable fun ArtistCardColumn() { Column { Text("Alfred Sisley") Text("3 minutes ago") } }
באופן דומה, אפשר להשתמש בRow
כדי למקם פריטים במסך באופן אופקי. גם Column
וגם Row
תומכים בהגדרת היישור של הרכיבים שהם מכילים.
@Composable fun ArtistCardRow(artist: Artist) { Row(verticalAlignment = Alignment.CenterVertically) { Image(bitmap = artist.image, contentDescription = "Artist image") Column { Text(artist.name) Text(artist.lastSeenOnline) } } }
משתמשים ב-Box
כדי להציב רכיבים זה על גבי זה. Box
תומך גם בהגדרת התאמה ספציפית של הרכיבים שהוא מכיל.
@Composable fun ArtistAvatar(artist: Artist) { Box { Image(bitmap = artist.image, contentDescription = "Artist image") Icon(Icons.Filled.Check, contentDescription = "Check mark") } }
לרוב, אבני הבניין האלה מספיקות. אתם יכולים לכתוב פונקציה משלכם שאפשר לשלב כדי לשלב את הפריסות האלה לפריסת מפורטת יותר שמתאימה לאפליקציה שלכם.
כדי להגדיר את המיקום של הצאצאים בתוך Row
, מגדירים את הארגומנטים horizontalArrangement
ו-verticalAlignment
. עבור Column
, מגדירים את הארגומנטים verticalArrangement
ו-horizontalAlignment
:
@Composable fun ArtistCardArrangement(artist: Artist) { Row( verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.End ) { Image(bitmap = artist.image, contentDescription = "Artist image") Column { /*...*/ } } }
מודל הפריסה
במודל הפריסה, עץ ממשק המשתמש מסודר בכרטיס אחד. קודם כל צומת צריך למדוד את עצמו, ורק אז למדוד ילדים באופן רקורסיבי, תוך העברת מגבלות גודל במורד העץ לילדים. לאחר מכן, המערכת קובעת את הגודל והמיקום של צמתים של עלים, וההוראות לגבי הגודל והמיקום מוחזרות בחזרה למעלה בעץ.
בקצרה, הורים מודדים את גודלם לפני ילדיהם, אבל את הגודל שלהם נקבעים אחרי הילדים.
נבחן את פונקציית SearchResult
הבאה.
@Composable fun SearchResult() { Row { Image( // ... ) Column { Text( // ... ) Text( // ... ) } } }
הפונקציה הזו מניבה את עץ ממשק המשתמש הבא.
SearchResult
Row
Image
Column
Text
Text
בדוגמה SearchResult
, פריסת העץ של ממשק המשתמש היא לפי הסדר הבא:
- צומת הרמה הבסיסית (root)
Row
מתבקש לבצע מדידה. - צומת הבסיס
Row
מבקש מהצאצא הראשון שלו,Image
, לבצע מדידה. Image
הוא צומת עלה (כלומר, אין לו צאצאים), ולכן הוא מדווח על גודל ומחזיר הוראות מיקום.- צומת הבסיס
Row
מבקש מהצאצא השני שלו,Column
, לבצע מדידה. - הצומת
Column
מבקש מהצאצא הראשון שלו מסוגText
לבצע מדידה. - הצומת הראשון מסוג
Text
הוא צומת עלה, ולכן הוא מדווח על גודל ומחזיר הוראות מיקום. - הצומת
Column
מבקש מהצאצא השניText
לבצע מדידה. - הצומת השני של
Text
הוא צומת עלה, ולכן הוא מדווח על גודל ומחזיר הוראות מיקום. - עכשיו, אחרי שהצומת
Column
מדד את הצאצאים שלו, קבע את הגודל שלהם והציב אותם, הוא יכול לקבוע את הגודל והמיקום שלו. - עכשיו, אחרי שמדדנו את הגודל של הצאצאים של צומת הבסיס
Row
, הנחנו אותם והחלטנו על המיקום שלהם, אפשר לקבוע את הגודל והמיקום של צומת הבסיס.
ביצועים
כדי להשיג ביצועים גבוהים, Compose מודד את הצאצאים רק פעם אחת. מדידה ב-Single-pass טובה לביצועים, ומאפשרת ל-Compose לטפל ביעילות בעצים עמוקים של ממשק משתמש. אם רכיב מסוים מודד את הצאצא שלו פעמיים, והצאצא הזה מודד כל אחד מהצאצאים שלו פעמיים וכן הלאה, ניסיון אחד לתכנן פריסה של ממשק משתמש שלם ידרוש הרבה עבודה, ויהיה קשה לשמור על ביצועים טובים באפליקציה.
אם מסיבה כלשהי צריך כמה מדידות בפריסה, Compose מציע מערכת מיוחדת, מדידות מובנות. מידע נוסף על התכונה הזו זמין במאמר מדידות מובנות בפריסות של Compose.
מכיוון שמדידה ומיקום הם שלבי משנה נפרדים של תהליך הבדיקה של הפריסה, אפשר לבצע בנפרד שינויים שמשפיעים רק על מיקום הפריטים ולא על המדידה.
שימוש במודיפיקטורים בפריסות
כמו שצוין בקטע משנים את הניסוח, אפשר להשתמש במגבילים כדי לקשט או לשפר את התכנים הקומפוזביליים. תוספי התאמה אישית הם חיוניים להתאמה אישית של הפריסה. לדוגמה, כאן אנחנו משורשרים מספר רכיבי שינוי כדי להתאים אישית את ArtistCard
:
@Composable fun ArtistCardModifiers( artist: Artist, onClick: () -> Unit ) { val padding = 16.dp Column( Modifier .clickable(onClick = onClick) .padding(padding) .fillMaxWidth() ) { Row(verticalAlignment = Alignment.CenterVertically) { /*...*/ } Spacer(Modifier.size(padding)) Card( elevation = CardDefaults.cardElevation(defaultElevation = 4.dp), ) { /*...*/ } } }
בקוד שלמעלה, שימו לב לשימוש בפונקציות מודיפיקטור שונות יחד.
clickable
מאפשר לרכיב ה-Composable להגיב לקלט של המשתמש ולהציג תנודות.padding
יוצר רווח מסביב לאובייקט.fillMaxWidth
גורם לרכיב ה-Composable למלא את הרוחב המקסימלי שהוגדר לו על ידי ההורה שלו.size()
מציין את הרוחב והגובה המועדפים של רכיב.
פריסות שניתן לגלול בהן
מידע נוסף על פריסות שניתן לגלול בהן זמין במסמכי התיעוד של תנועות הכתיבה.
פריסות רספונסיביות
צריך לתכנן את הפריסה בהתאם לכיוונים שונים של המסך ולגדלים שונים של גורם הצורה. Compose מציע כמה מנגנונים מוכנים לשימוש שבעזרתם תוכלו להתאים את הפריסות הניתנות ליצירה להגדרות מסך שונות.
אילוצים
כדי לדעת מהם האילוצים שמגיעים מהרכיב ההורה ולתכנן את הפריסה בהתאם, אפשר להשתמש ב-BoxWithConstraints
. מגבלות המדידה יכולות להיכלל בהיקף התוכן lambda. אפשר להשתמש במגבלות המדידה האלו כדי להרכיב פריסות שונות להגדרות שונות של המסך:
@Composable fun WithConstraintsComposable() { BoxWithConstraints { Text("My minHeight is $minHeight while my maxWidth is $maxWidth") } }
פריסות שמבוססות על משבצות
ב-Compose יש מגוון רחב של רכיבים שניתנים לשילוב (composables) שמבוססים על Material Design, עם יחסי התלות androidx.compose.material:material
(שכלולים כשיוצרים פרויקט Compose ב-Android Studio) כדי להקל על בניית ממשק המשתמש. מקבלים רכיבים כמו Drawer
, FloatingActionButton
ו-TopAppBar
.
רכיבי Material משתמשים הרבה בממשקי API של משבצות, דפוס ש-Compose מציג כדי להוסיף שכבת התאמה אישית מעל רכיבים שניתנים לשילוב. הגישה הזו הופכת את הרכיבים לגמישים יותר, כי הם מקבלים רכיב צאצא שיכול להגדיר את עצמו במקום לחשוף כל פרמטר של תצורת הצאצא.
יחידות הקיבולת משאירות מקום ריק בממשק המשתמש שהמפתח יכול למלא לפי רצון. לדוגמה, אלה הן המשבצות שאפשר להתאים אישית ב-TopAppBar
:
בדרך כלל, רכיבים מורכבים מקבלים פונקציית lambda מורכבת מסוג content
( content: @Composable
() -> Unit
). ממשקי API של משבצות חושפים כמה פרמטרים מסוג content
לשימושים ספציפיים.
לדוגמה, TopAppBar
מאפשר לכם לספק את התוכן עבור title
,
navigationIcon
ו-actions
.
לדוגמה, Scaffold
מאפשר להטמיע ממשק משתמש עם מבנה הפריסה הבסיסי של Material Design.
Scaffold
מספק משבצות לרכיבים הנפוצים ביותר של Material, כמו TopAppBar
,
BottomAppBar
,
FloatingActionButton
,
ו-Drawer
. באמצעות Scaffold
קל לוודא שהרכיבים האלה ממוקמים בצורה נכונה ופועלים יחד בצורה תקינה.
@Composable fun HomeScreen(/*...*/) { ModalNavigationDrawer(drawerContent = { /* ... */ }) { Scaffold( topBar = { /*...*/ } ) { contentPadding -> // ... } } }
מומלץ עבורך
- הערה: טקסט הקישור מוצג כאשר JavaScript מושבת
- הרכבת משתנים
- Kotlin ל-Jetpack פיתוח נייטיב
- רכיבים ופריסות של חומר לימוד