מידע בסיסי על הפריסה של הרכב

עם Jetpack פיתוח נייטיב קל יותר לעצב ולבנות את ממשק המשתמש של האפליקציה. אימייל חדש הופכת את המצב לרכיבי ממשק משתמש באמצעות:

  1. הרכב של יסודות
  2. פריסה של רכיבים
  3. שרטוט של אלמנטים

הרכבת מצב טרנספורמציה לממשק משתמש באמצעות הרכבה, פריסה ושרטוט

מסמך זה מתמקד בפריסת האלמנטים ומסביר חלק מהבניין בלוקים ש- Compose מספק כדי לעזור לך לפרוס את הרכיבים בממשק המשתמש.

יעדי הפריסות של 'כתיבה'

להטמעה של 'Jetpack פיתוח נייטיב' של מערכת הפריסה יש שני יעדים עיקריים:

עקרונות בסיסיים של פונקציות קומפוזביליות

פונקציות קומפוזביליות הן אבן הבניין הבסיסית של הכתיבה. תוכן קומפוזבילי היא פונקציה שפולטת את Unit שמתארת חלק מסוים מממשק המשתמש. מקבלת קלט מסוים ויוצרת את מה שמוצג במסך. לקבלת מידע נוסף על תכנים קומפוזביליים, כדאי לקרוא את המודל של המודל.

פונקציה קומפוזבילית עשויה ליצור מספר רכיבים בממשק המשתמש. עם זאת, אם לא לספק הנחיות לגבי אופן הסידור שלהן, 'כתיבה' עשויה לארגן את באופן שלא מוצא חן בעיניך. לדוגמה, הקוד הזה יוצר שני טקסטים רכיבים:

@Composable
fun ArtistCard() {
    Text("Alfred Sisley")
    Text("3 minutes ago")
}

ללא הנחיות לגבי אופן הסידור שלהן, 'כתיבת מקבצים' של רכיבי הטקסט זה על גבי זה, באופן שהופך אותם לבלתי קריאים:

שני רכיבי טקסט שמונחים אחד על גבי השני, כך שהטקסט לא קריא

הכלי 'פיתוח נייטיב' מספק אוסף של פריסות מוכנות לשימוש שיעזרו לכם לארגן את רכיבים בממשק המשתמש ומקלים על ההגדרה של פריסות ייחודיות משלכם.

רכיבי פריסה רגילה

במקרים רבים אפשר פשוט להשתמש בפריסה הרגילה של רכיבים.

כדאי להשתמש 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, פריסת העץ של ממשק המשתמש מבוססת על הסדר הבא:

  1. צומת הרמה הבסיסית (root) Row מתבקש למדוד.
  2. צומת הרמה הבסיסית (root) Row מבקש מהצאצא הראשון, Image, למדוד.
  3. Image הוא צומת עלה (כלומר, אין לו צאצאים), ולכן הוא מדווח על גודל והוראות להצבה להחזרה.
  4. צומת הרמה הבסיסית (root) Row מבקש מהצאצא השני, Column, למדוד.
  5. הצומת Column מבקש מהצאצא הראשון של Text לבצע מדידה.
  6. הצומת הראשון Text הוא צומת עלה, לכן הוא מדווח על גודל ומחזיר הוראות להצבה.
  7. הצומת Column מבקש מהצאצא השני (Text) שלו למדוד.
  8. הצומת השני של Text הוא צומת עלה, לכן הוא מדווח על גודל ומחזיר הוראות להצבה.
  9. עכשיו, אחרי שהצומת Column מדד, גודל וציב את הצאצאים שלו, יכול לקבוע את הגודל והמיקום שלו.
  10. עכשיו, אחרי שצומת הרמה הבסיסית (root) Row מדד, גודל והציב את הצאצאים שלו, יכול לקבוע את הגודל והמיקום שלו.

סדר המדידה, שינוי הגודל והמיקום בעץ ממשק המשתמש של תוצאות החיפוש

ביצועים

התכונה 'פיתוח נייטיב' משיגה ביצועים גבוהים על ידי מדידת ילדים רק פעם אחת. כרטיס יחיד מדידה טובה לביצועים, ומאפשרת ל'כתיבה' לטפל ביעילות בשגיאות עץ UI. אם רכיב מדד את הצאצא שלו פעמיים והצאצא מדד כל אחד מהמדדים את הצאצאים שלו פעמיים וכן הלאה, ניסיון אחד לפרוס ממשק משתמש שלם לביצוע עבודה רבה, מה שמקשה עלינו לשמור על ביצועי האפליקציה.

אם לפריסה מסוימת נדרשות כמה מדידות מסיבה כלשהי, התכונה 'כתיבה' תציע היא מערכת מיוחדת, מדידות פנימיות. מידע נוסף על התכונה הזו בקטע מדידות פנימיות של תהליך הכתיבה .

מדידה ומיקום הם שלבי משנה נפרדים של אישור הפריסה, לכן כל ניתן לבצע שינויים שמשפיעים רק על המיקום של פריטים ולא על מדידה בנפרד.

שימוש במקשי הצירוף בפריסות

כמו שצוין בקטע מגבילי כתיבה, אפשר להשתמש מגבילים כדי לקשט או להרחיב את התכנים הקומפוזביליים. מגבילי התאמה הם הכרחיים להתאמה אישית של הפריסה. לדוגמה, כאן אנחנו יוצרים שרשור של כמה התאמות כדי להתאים אישית את 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 יוצר תגובה קומפוזבילית לקלט של משתמש ומראה גל.
  • padding תופסת רווח מסביב לרכיב.
  • fillMaxWidth הופך את המילוי הקומפוזבילי לרוחב המקסימלי שניתן לו ההורה שלו.
  • size() מציין את הרוחב והגובה המועדפים של האלמנט.

פריסות שניתן לגלול

למידע נוסף על פריסות שניתנות לגלילה ב תיעוד של תנועות לכתיבה.

כדי לקבל מידע על רשימות או רשימות עצלניות, ניתן לעיין מסמכי תיעוד של כתיבת רשימות.

פריסות רספונסיביות

צריך לתכנן את הפריסה תוך התייחסות לכיוונים שונים של המסך ובגודל של גורם צורה. נסחו מוצרים ייחודיים באמצעות מספר מנגנונים שיעזרו לכם להתאים את הפריסות הקומפוזביליות לתצורות מסך שונות.

מגבלות

כדי לדעת אילו מגבלות מגיעות מההורה ולעצב את הפריסה בהתאם, תוכלו להשתמש ב-BoxWithConstraints. המדידה מגבלות נמצאים בהיקף התוכן lambda. אפשר להשתמש במדידות האלה אילוצים להרכיב פריסות שונות לתצורות מסך שונות:

@Composable
fun WithConstraintsComposable() {
    BoxWithConstraints {
        Text("My minHeight is $minHeight while my maxWidth is $maxWidth")
    }
}

פריסות המבוססות על משבצות

התכונה 'פיתוח נייטיב' מספקת מגוון גדול של תכנים קומפוזביליים שמבוססים על חומר עיצוב באמצעות תלות של androidx.compose.material:material (כלולה כשיוצרים כתיבת פרויקט ב-Android Studio) כדי לבנות ממשק משתמש בקלות. רכיבים אוהבים Drawer FloatingActionButton, ו-TopAppBar סופקו.

יש שימוש נרחב בממשקי API של יחידות קיבולת (Slot) ברכיבי החומר, והתבנית החדשה מאפשרת כדי להוסיף שכבה של התאמה אישית מעל תכנים קומפוזביליים. בגישה הזאת רכיבים גמישים יותר, מכיוון שהם מקבלים רכיב צאצא שיכול להגדיר עצמו, במקום לחשוף את כל פרמטר ההגדרה של הצאצא. יחידות הקיבולת משאירות מקום ריק בממשק המשתמש שהמפתח יכול למלא לפי רצון. עבור אלה המשבצות שאפשר להתאים אישית TopAppBar:

תרשים שמראה את מיקומי המשבצות הזמינים בסרגל האפליקציות של רכיבי Material Material

תכנים קומפוזביליים בדרך כלל מקבלים lambda קומפוזביליות של content ( content: @Composable () -> Unit). ממשקי API של יחידת קיבולת (Slot) חושפים פרמטרים מרובים של content לשימושים ספציפיים. לדוגמה, הפקודה TopAppBar מאפשרת לספק את התוכן של title, navigationIcon ו-actions.

לדוגמה, Scaffold מאפשר ליישם ממשק משתמש עם מבנה הפריסה הבסיסי של Material Design. Scaffoldמספק חריצים לרכיבי החומר ברמה העליונה הנפוצים ביותר, כמו TopAppBar, BottomAppBar, FloatingActionButton, וגם Drawer. על ידי שימוש Scaffold, קל לוודא שהרכיבים האלה ממוקמים כראוי פועלות יחד כראוי.

האפליקציה לדוגמה של JetNews, שמשתמשת ב-Scaffold כדי למקם מספר אלמנטים

@Composable
fun HomeScreen(/*...*/) {
    ModalNavigationDrawer(drawerContent = { /* ... */ }) {
        Scaffold(
            topBar = { /*...*/ }
        ) { contentPadding ->
            // ...
        }
    }
}