מדריך

מדריך לכתיבה ב-Jetpack

'Jetpack פיתוח נייטיב' היא ערכת כלים מודרנית לפיתוח ממשק משתמש מותאם ל-Android. Jetpack פיתוח נייטיב מפשט ומאיץ פיתוח של ממשק משתמש ב-Android עם פחות תכנות, כלים חזקים וממשקי API אינטואיטיביים של Kotlin.

במדריך הזה תבנה רכיב פשוט של ממשק משתמש עם פונקציות הצהרתיות. לא תוכל לערוך פריסות XML או להשתמש בעורך הפריסה. במקום זאת, תקראו לתוכן קומפוזבילי כדי להגדיר אילו רכיבים אתם רוצים, והמהדר (compiler) לכתיבה יעשה את השאר.

תצוגה מקדימה מלאה
תצוגה מקדימה מלאה

שיעור 1: פונקציות קומפוזביליות

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

הוספת רכיב טקסט

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

קודם כל, מציגים את הכיתוב "Hello World! " של טקסט על ידי הוספת רכיב טקסט בתוך אמצעי תשלום אחד (onCreate). כדי לעשות את זה, מגדירים תוכן לחסום אותו, ולקרוא ל- Text פונקציה קומפוזבילית. בלוק setContent מגדיר את פריסת הפעילות כאשר פונקציות קומפוזביליות נקראות. אפשר לקרוא לפונקציות קומפוזביליות רק מפונקציות קומפוזביליות אחרות למשימות ספציפיות.

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

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.material3.Text

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            Text("Hello world!")
        }
    }
}
  
צפייה בתצוגה המקדימה
הסתרת התצוגה המקדימה

הגדרת פונקציה קומפוזבילית

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

// ...
import androidx.compose.runtime.Composable

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MessageCard("Android")
        }
    }
}

@Composable
fun MessageCard(name: String) {
    Text(text = "Hello $name!")
}

  
צפייה בתצוגה המקדימה
הסתרת התצוגה המקדימה

תצוגה מקדימה של הפונקציה ב-Android Studio

ההערה @Preview מאפשרת תצוגה מקדימה של הפונקציות הקומפוזביליות ב-Android Studio ללא צורך לפתח ולהתקין את האפליקציה במכשיר Android או באמולטור. צריך להשתמש בהערה בפונקציה קומפוזבילית שלא מקבלת פרמטרים. בשביל זה כי אי אפשר להציג תצוגה מקדימה של הפונקציה MessageCard ישירות. במקום זאת, צריך ליצור פונקציה שנייה בשם PreviewMessageCard, שיתקשר MessageCard עם פרמטר מתאים. מוסיפים את הערה אחת (@Preview) לפני @Composable.

// ...
import androidx.compose.ui.tooling.preview.Preview

@Composable
fun MessageCard(name: String) {
    Text(text = "Hello $name!")
}

@Preview
@Composable
fun PreviewMessageCard() {
    MessageCard("Android")
}
  
צפייה בתצוגה המקדימה
הסתרת התצוגה המקדימה

בונים מחדש את הפרויקט. האפליקציה עצמה לא משתנה, מפני שה לא ניתן להפעיל את הפונקציה PreviewMessageCard לשום מקום. אבל ב-Android Studio מוסיפים חלון תצוגה מקדימה שניתן להרחיב על ידי לחיצה על (עיצוב/קוד). בחלון הזה מוצגת תצוגה מקדימה של רכיבי ממשק המשתמש שנוצרו על ידי תוכן קומפוזבילי פונקציות שמסומנות בהערה @Preview. לעדכון את התצוגות המקדימות בכל שלב, לחצו על הלחצן 'רענון' בחלק העליון של חלון התצוגה המקדימה.

תצוגה מקדימה של פונקציה קומפוזבילית ב-Android Studio
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.material3.Text

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            Text("Hello world!")
        }
    }
}
  
צפייה בתצוגה המקדימה
הסתרת התצוגה המקדימה
// ...
import androidx.compose.runtime.Composable

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MessageCard("Android")
        }
    }
}

@Composable
fun MessageCard(name: String) {
    Text(text = "Hello $name!")
}

  
צפייה בתצוגה המקדימה
הסתרת התצוגה המקדימה
// ...
import androidx.compose.ui.tooling.preview.Preview

@Composable
fun MessageCard(name: String) {
    Text(text = "Hello $name!")
}

@Preview
@Composable
fun PreviewMessageCard() {
    MessageCard("Android")
}
  
צפייה בתצוגה המקדימה
הסתרת התצוגה המקדימה
תצוגה מקדימה של פונקציה קומפוזבילית ב-Android Studio

שיעור 2: פריסות

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

הוספת כמה טקסטים

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

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

// ...

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MessageCard(Message("Android", "Jetpack Compose"))
        }
    }
}

data class Message(val author: String, val body: String)

@Composable
fun MessageCard(msg: Message) {
    Text(text = msg.author)
    Text(text = msg.body)
}

@Preview
@Composable
fun PreviewMessageCard() {
    MessageCard(
        msg = Message("Lexi", "Hey, take a look at Jetpack Compose, it's great!")
    )
}

  
צפייה בתצוגה המקדימה
הסתרת התצוגה המקדימה

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

שימוש בעמודה

הפונקציה Column מאפשרת לארגן רכיבים במאונך. להוסיף את Column אל MessageCard.
אפשר להשתמש ב- Row כדי לארגן פריטים לרוחב Box כדי לערום רכיבים.

// ...
import androidx.compose.foundation.layout.Column

@Composable
fun MessageCard(msg: Message) {
    Column {
        Text(text = msg.author)
        Text(text = msg.body)
    }
}
צפייה בתצוגה המקדימה
הסתרת התצוגה המקדימה

הוספת רכיב תמונה

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

// ...
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Row
import androidx.compose.ui.res.painterResource

@Composable
fun MessageCard(msg: Message) {
    Row {
        Image(
            painter = painterResource(R.drawable.profile_picture),
            contentDescription = "Contact profile picture",
        )
    
       Column {
            Text(text = msg.author)
            Text(text = msg.body)
        }
  
    }
  
}
  
צפייה בתצוגה המקדימה
הסתרת התצוגה המקדימה

הגדרת הפריסה

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

// ...
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.unit.dp

@Composable
fun MessageCard(msg: Message) {
    // Add padding around our message
    Row(modifier = Modifier.padding(all = 8.dp)) {
        Image(
            painter = painterResource(R.drawable.profile_picture),
            contentDescription = "Contact profile picture",
            modifier = Modifier
                // Set image size to 40 dp
                .size(40.dp)
                // Clip image to be shaped as a circle
                .clip(CircleShape)
        )

        // Add a horizontal space between the image and the column
        Spacer(modifier = Modifier.width(8.dp))

        Column {
            Text(text = msg.author)
            // Add a vertical space between the author and message texts
            Spacer(modifier = Modifier.height(4.dp))
            Text(text = msg.body)
        }
    }
}
  
צפייה בתצוגה המקדימה
הסתרת התצוגה המקדימה
// ...

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MessageCard(Message("Android", "Jetpack Compose"))
        }
    }
}

data class Message(val author: String, val body: String)

@Composable
fun MessageCard(msg: Message) {
    Text(text = msg.author)
    Text(text = msg.body)
}

@Preview
@Composable
fun PreviewMessageCard() {
    MessageCard(
        msg = Message("Lexi", "Hey, take a look at Jetpack Compose, it's great!")
    )
}

  
צפייה בתצוגה המקדימה
הסתרת התצוגה המקדימה
תצוגה מקדימה של שתי תכנים קומפוזביליים חופפים של טקסט
// ...
import androidx.compose.foundation.layout.Column

@Composable
fun MessageCard(msg: Message) {
    Column {
        Text(text = msg.author)
        Text(text = msg.body)
    }
}
צפייה בתצוגה המקדימה
הסתרת התצוגה המקדימה
// ...
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Row
import androidx.compose.ui.res.painterResource

@Composable
fun MessageCard(msg: Message) {
    Row {
        Image(
            painter = painterResource(R.drawable.profile_picture),
            contentDescription = "Contact profile picture",
        )
    
       Column {
            Text(text = msg.author)
            Text(text = msg.body)
        }
  
    }
  
}
  
צפייה בתצוגה המקדימה
הסתרת התצוגה המקדימה
// ...
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.unit.dp

@Composable
fun MessageCard(msg: Message) {
    // Add padding around our message
    Row(modifier = Modifier.padding(all = 8.dp)) {
        Image(
            painter = painterResource(R.drawable.profile_picture),
            contentDescription = "Contact profile picture",
            modifier = Modifier
                // Set image size to 40 dp
                .size(40.dp)
                // Clip image to be shaped as a circle
                .clip(CircleShape)
        )

        // Add a horizontal space between the image and the column
        Spacer(modifier = Modifier.width(8.dp))

        Column {
            Text(text = msg.author)
            // Add a vertical space between the author and message texts
            Spacer(modifier = Modifier.height(4.dp))
            Text(text = msg.body)
        }
    }
}
  
צפייה בתצוגה המקדימה
הסתרת התצוגה המקדימה

שיעור 3: עיצוב חדשני

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

שימוש בעיצוב חדשני (Material Design)

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

Jetpack Compose מספק הטמעה של Material Design 3 ושל רכיבי ממשק המשתמש שלו . כך יש לך אפשרות לשפר את המראה של MessageCard קומפוזבילי באמצעות עיצוב Material Design.

כדי להתחיל, צריך לתחום את הפונקציה MessageCard עם עיצוב של חומר לימוד שנוצר בפרויקט שלך, ComposeTutorialTheme, וגם Surface. אפשר לעשות זאת גם ב@Preview וגם setContent. הפעולה הזו תאפשר לתכנים הקומפוזביליים שלך כדי לרשת סגנונות כפי שהוגדרו בעיצוב של האפליקציה, וכך להבטיח עקביות בכל האפליקציה.

עיצוב חדשני (Material Design) בנוי סביב שלושה עמודי תווך: Color, Typography ו-Shape. צריך להוסיף אותן אחת אחרי השנייה.

הערה: התבנית של פעילות הכתיבה הריקה יוצרת עיצוב ברירת מחדל לפרויקט. מאפשר להתאים אישית MaterialTheme אם נתתם לפרויקט שם שונה לכתוב מדריך. תוכלו למצוא את העיצוב המותאם אישית בקטע קובץ Theme.kt ב חבילת משנה ui.theme.

// ...

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            ComposeTutorialTheme {
                Surface(modifier = Modifier.fillMaxSize()) {
                    MessageCard(Message("Android", "Jetpack Compose"))
                }
            }
        }
    }
}

@Preview
@Composable
fun PreviewMessageCard() {
    ComposeTutorialTheme {
        Surface {
            MessageCard(
                msg = Message("Lexi", "Take a look at Jetpack Compose, it's great!")
            )
        }
    }
}


  
צפייה בתצוגה המקדימה
הסתרת התצוגה המקדימה

צבע

אפשר להשתמש ב-MaterialTheme.colorScheme כדי לעצב באמצעות צבעים עיצוב מוקף. אפשר להשתמש בערכים האלה מתוך העיצוב בכל מקום שבו צריך צבע. בדוגמה הזו נעשה שימוש בצבעי עיצוב דינמיים (מוגדרים על ידי העדפות המכשיר). כדי לשנות את זה, אפשר להגדיר את dynamicColor לערך false בקובץ MaterialTheme.kt.

מעצבים את הכותרת ומוסיפים גבול לתמונה.

// ...
import androidx.compose.foundation.border
import androidx.compose.material3.MaterialTheme

@Composable
fun MessageCard(msg: Message) {
   Row(modifier = Modifier.padding(all = 8.dp)) {
       Image(
           painter = painterResource(R.drawable.profile_picture),
           contentDescription = null,
           modifier = Modifier
               .size(40.dp)
               .clip(CircleShape)
               .border(1.5.dp, MaterialTheme.colorScheme.primary, CircleShape)
       )

       Spacer(modifier = Modifier.width(8.dp))

       Column {
           Text(
               text = msg.author,
               color = MaterialTheme.colorScheme.secondary
           )

           Spacer(modifier = Modifier.height(4.dp))
           Text(text = msg.body)
       }
   }
}

  
צפייה בתצוגה המקדימה
הסתרת התצוגה המקדימה

טיפוגרפיה

סגנונות טיפוגרפיה בחומרים זמינים בMaterialTheme, פשוט להוסיף אותם לתכנים הקומפוזביליים של Text.

// ...

@Composable
fun MessageCard(msg: Message) {
   Row(modifier = Modifier.padding(all = 8.dp)) {
       Image(
           painter = painterResource(R.drawable.profile_picture),
           contentDescription = null,
           modifier = Modifier
               .size(40.dp)
               .clip(CircleShape)
               .border(1.5.dp, MaterialTheme.colorScheme.primary, CircleShape)
       )
       Spacer(modifier = Modifier.width(8.dp))

       Column {
           Text(
               text = msg.author,
               color = MaterialTheme.colorScheme.secondary,
               style = MaterialTheme.typography.titleSmall
           )

           Spacer(modifier = Modifier.height(4.dp))

           Text(
               text = msg.body,
               style = MaterialTheme.typography.bodyMedium
           )
       }
   }
}

  
צפייה בתצוגה המקדימה
הסתרת התצוגה המקדימה

צורה

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

// ...
import androidx.compose.material3.Surface

@Composable
fun MessageCard(msg: Message) {
   Row(modifier = Modifier.padding(all = 8.dp)) {
       Image(
           painter = painterResource(R.drawable.profile_picture),
           contentDescription = null,
           modifier = Modifier
               .size(40.dp)
               .clip(CircleShape)
               .border(1.5.dp, MaterialTheme.colorScheme.primary, CircleShape)
       )
       Spacer(modifier = Modifier.width(8.dp))

       Column {
           Text(
               text = msg.author,
               color = MaterialTheme.colorScheme.secondary,
               style = MaterialTheme.typography.titleSmall
           )

           Spacer(modifier = Modifier.height(4.dp))

           Surface(shape = MaterialTheme.shapes.medium, shadowElevation = 1.dp) {
               Text(
                   text = msg.body,
                   modifier = Modifier.padding(all = 4.dp),
                   style = MaterialTheme.typography.bodyMedium
               )
           }
       }
   }
}

  
צפייה בתצוגה המקדימה
הסתרת התצוגה המקדימה

הפעלת העיצוב הכהה

עיצוב כהה (או מצב לילה) כדי להימנע מתצוגה בהירה במיוחד בלילה, או פשוט כדי לחסוך הסוללה של המכשיר. בזכות התמיכה ב-Material Design, Jetpack פיתוח נייטיב יכול להתמודד עם כברירת מחדל. שימוש בצבעים, בטקסט וברקעים ב-Material Design להתאים את עצמו לרקע הכהה.

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

יש להוסיף הערה חדשה לתצוגה מקדימה ולהפעיל את מצב לילה.

// ...
import android.content.res.Configuration

@Preview(name = "Light Mode")
@Preview(
    uiMode = Configuration.UI_MODE_NIGHT_YES,
    showBackground = true,
    name = "Dark Mode"
)
@Composable
fun PreviewMessageCard() {
   ComposeTutorialTheme {
    Surface {
      MessageCard(
        msg = Message("Lexi", "Hey, take a look at Jetpack Compose, it's great!")
      )
    }
   }
}
  
צפייה בתצוגה המקדימה
הסתרת התצוגה המקדימה

אפשרויות הצבעים של העיצוב הבהיר והעיצוב הכהה מוגדרות בסביבת הפיתוח המשולבת (IDE) קובץ Theme.kt.

עד עכשיו יצרתם רכיב בממשק המשתמש של ההודעה שמציג תמונה ושני טקסטים עם והוא נראה טוב גם בעיצובים בהירים וגם בעיצוב כהה!

// ...
import android.content.res.Configuration

@Preview(name = "Light Mode")
@Preview(
    uiMode = Configuration.UI_MODE_NIGHT_YES,
    showBackground = true,
    name = "Dark Mode"
)
@Composable
fun PreviewMessageCard() {
   ComposeTutorialTheme {
    Surface {
      MessageCard(
        msg = Message("Lexi", "Hey, take a look at Jetpack Compose, it's great!")
      )
    }
   }
}
  
צפייה בתצוגה המקדימה
הסתרת התצוגה המקדימה
// ...

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            ComposeTutorialTheme {
                Surface(modifier = Modifier.fillMaxSize()) {
                    MessageCard(Message("Android", "Jetpack Compose"))
                }
            }
        }
    }
}

@Preview
@Composable
fun PreviewMessageCard() {
    ComposeTutorialTheme {
        Surface {
            MessageCard(
                msg = Message("Lexi", "Take a look at Jetpack Compose, it's great!")
            )
        }
    }
}


  
צפייה בתצוגה המקדימה
הסתרת התצוגה המקדימה
// ...
import androidx.compose.foundation.border
import androidx.compose.material3.MaterialTheme

@Composable
fun MessageCard(msg: Message) {
   Row(modifier = Modifier.padding(all = 8.dp)) {
       Image(
           painter = painterResource(R.drawable.profile_picture),
           contentDescription = null,
           modifier = Modifier
               .size(40.dp)
               .clip(CircleShape)
               .border(1.5.dp, MaterialTheme.colorScheme.primary, CircleShape)
       )

       Spacer(modifier = Modifier.width(8.dp))

       Column {
           Text(
               text = msg.author,
               color = MaterialTheme.colorScheme.secondary
           )

           Spacer(modifier = Modifier.height(4.dp))
           Text(text = msg.body)
       }
   }
}

  
צפייה בתצוגה המקדימה
הסתרת התצוגה המקדימה
// ...

@Composable
fun MessageCard(msg: Message) {
   Row(modifier = Modifier.padding(all = 8.dp)) {
       Image(
           painter = painterResource(R.drawable.profile_picture),
           contentDescription = null,
           modifier = Modifier
               .size(40.dp)
               .clip(CircleShape)
               .border(1.5.dp, MaterialTheme.colorScheme.primary, CircleShape)
       )
       Spacer(modifier = Modifier.width(8.dp))

       Column {
           Text(
               text = msg.author,
               color = MaterialTheme.colorScheme.secondary,
               style = MaterialTheme.typography.titleSmall
           )

           Spacer(modifier = Modifier.height(4.dp))

           Text(
               text = msg.body,
               style = MaterialTheme.typography.bodyMedium
           )
       }
   }
}

  
צפייה בתצוגה המקדימה
הסתרת התצוגה המקדימה
// ...
import androidx.compose.material3.Surface

@Composable
fun MessageCard(msg: Message) {
   Row(modifier = Modifier.padding(all = 8.dp)) {
       Image(
           painter = painterResource(R.drawable.profile_picture),
           contentDescription = null,
           modifier = Modifier
               .size(40.dp)
               .clip(CircleShape)
               .border(1.5.dp, MaterialTheme.colorScheme.primary, CircleShape)
       )
       Spacer(modifier = Modifier.width(8.dp))

       Column {
           Text(
               text = msg.author,
               color = MaterialTheme.colorScheme.secondary,
               style = MaterialTheme.typography.titleSmall
           )

           Spacer(modifier = Modifier.height(4.dp))

           Surface(shape = MaterialTheme.shapes.medium, shadowElevation = 1.dp) {
               Text(
                   text = msg.body,
                   modifier = Modifier.padding(all = 4.dp),
                   style = MaterialTheme.typography.bodyMedium
               )
           }
       }
   }
}

  
צפייה בתצוגה המקדימה
הסתרת התצוגה המקדימה
// ...
import android.content.res.Configuration

@Preview(name = "Light Mode")
@Preview(
    uiMode = Configuration.UI_MODE_NIGHT_YES,
    showBackground = true,
    name = "Dark Mode"
)
@Composable
fun PreviewMessageCard() {
   ComposeTutorialTheme {
    Surface {
      MessageCard(
        msg = Message("Lexi", "Hey, take a look at Jetpack Compose, it's great!")
      )
    }
   }
}
  
צפייה בתצוגה המקדימה
הסתרת התצוגה המקדימה
תצוגה מקדימה שמציגה תכנים קומפוזביליים בעיצוב בהיר וגם כהה.

שיעור 4: רשימות ואנימציות

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

איך יוצרים רשימת הודעות

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

בקטע הקוד הזה ניתן לראות שב-LazyColumn יש צאצא אחד (items). נדרש List כפרמטר וה-lambda שלו מקבל פרמטר שנקרא message (היכולת שלנו הייתה לקבל ונותנים לו את השם איך שנרצה) שהוא מופע של Message. בקיצור, lambda קריאה לכל פריט List מעתיקים את מערך נתונים לדוגמה לפרויקט שלכם כדי לעזור לכם להתחיל את השיחה במהירות.

// ...
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items

@Composable
fun Conversation(messages: List<Message>) {
    LazyColumn {
        items(messages) { message ->
            MessageCard(message)
        }
    }
}

@Preview
@Composable
fun PreviewConversation() {
    ComposeTutorialTheme {
        Conversation(SampleData.conversationSample)
    }
}

  
צפייה בתצוגה המקדימה
הסתרת התצוגה המקדימה

הצגת אנימציה של ההודעות בזמן הרחבה

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

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

על ידי שימוש בממשקי ה-API של מצב 'כתיבה', כמו remember ו- mutableStateOf, כל שינוי במצב יגרום לעדכון אוטומטי של ממשק המשתמש.

הערה: יש להוסיף את פעולות הייבוא הבאות כדי להשתמש בצורה נכונה בפונקציה Kotlin תחביר של הנכסים שהוענקה הרשאה לנהל אותם (מילת המפתח by). Alt+Enter או Option+Enter מוסיף אותם. עבורך.
import androidx.compose.runtime.getValue import androidx.compose.runtime.setValue

// ...
import androidx.compose.foundation.clickable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue

class MainActivity : ComponentActivity() {
   override fun onCreate(savedInstanceState: Bundle?) {
       super.onCreate(savedInstanceState)
       setContent {
           ComposeTutorialTheme {
               Conversation(SampleData.conversationSample)
           }
       }
   }
}

@Composable
fun MessageCard(msg: Message) {
    Row(modifier = Modifier.padding(all = 8.dp)) {
        Image(
            painter = painterResource(R.drawable.profile_picture),
            contentDescription = null,
            modifier = Modifier
                .size(40.dp)
                .clip(CircleShape)
                .border(1.5.dp, MaterialTheme.colorScheme.primary, CircleShape)
        )
        Spacer(modifier = Modifier.width(8.dp))

        // We keep track if the message is expanded or not in this
        // variable
        var isExpanded by remember { mutableStateOf(false) }

        // We toggle the isExpanded variable when we click on this Column
        Column(modifier = Modifier.clickable { isExpanded = !isExpanded }) {
            Text(
                text = msg.author,
                color = MaterialTheme.colorScheme.secondary,
                style = MaterialTheme.typography.titleSmall
            )

            Spacer(modifier = Modifier.height(4.dp))

            Surface(
                shape = MaterialTheme.shapes.medium,
                shadowElevation = 1.dp,
            ) {
                Text(
                    text = msg.body,
                    modifier = Modifier.padding(all = 4.dp),
                    // If the message is expanded, we display all its content
                    // otherwise we only display the first line
                    maxLines = if (isExpanded) Int.MAX_VALUE else 1,
                    style = MaterialTheme.typography.bodyMedium
                )
            }
        }
    }
}

  
צפייה בתצוגה המקדימה
הסתרת התצוגה המקדימה

עכשיו ניתן לשנות את הרקע של תוכן ההודעה בהתאם isExpanded כשאנחנו לוחצים על הודעה. תשתמשו מגביל clickable לטיפול באירועי קליק ב קומפוזבילי. במקום להחליף רק את צבע הרקע של Surface, תתבצע אנימציה של צבע הרקע לפי משנה את הערך שלו בהדרגה MaterialTheme.colorScheme.surface עד MaterialTheme.colorScheme.primary ולהפך. כדי לעשות את זה, תשתמשו בפונקציה animateColorAsState. לבסוף, ישתמש בתכונת הצירוף animateContentSize כדי להוסיף אנימציה גודל מאגר ההודעות בצורה חלקה:

// ...
import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.animateContentSize

@Composable
fun MessageCard(msg: Message) {
    Row(modifier = Modifier.padding(all = 8.dp)) {
        Image(
            painter = painterResource(R.drawable.profile_picture),
            contentDescription = null,
            modifier = Modifier
                .size(40.dp)
                .clip(CircleShape)
                .border(1.5.dp, MaterialTheme.colorScheme.secondary, CircleShape)
        )
        Spacer(modifier = Modifier.width(8.dp))

        // We keep track if the message is expanded or not in this
        // variable
        var isExpanded by remember { mutableStateOf(false) }
        // surfaceColor will be updated gradually from one color to the other
        val surfaceColor by animateColorAsState(
            if (isExpanded) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.surface,
        )

        // We toggle the isExpanded variable when we click on this Column
        Column(modifier = Modifier.clickable { isExpanded = !isExpanded }) {
            Text(
                text = msg.author,
                color = MaterialTheme.colorScheme.secondary,
                style = MaterialTheme.typography.titleSmall
            )

            Spacer(modifier = Modifier.height(4.dp))

            Surface(
                shape = MaterialTheme.shapes.medium,
                shadowElevation = 1.dp,
                // surfaceColor color will be changing gradually from primary to surface
                color = surfaceColor,
                // animateContentSize will change the Surface size gradually
                modifier = Modifier.animateContentSize().padding(1.dp)
            ) {
                Text(
                    text = msg.body,
                    modifier = Modifier.padding(all = 4.dp),
                    // If the message is expanded, we display all its content
                    // otherwise we only display the first line
                    maxLines = if (isExpanded) Int.MAX_VALUE else 1,
                    style = MaterialTheme.typography.bodyMedium
                )
            }
        }
    }
}

  
צפייה בתצוגה המקדימה
הסתרת התצוגה המקדימה
// ...
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items

@Composable
fun Conversation(messages: List<Message>) {
    LazyColumn {
        items(messages) { message ->
            MessageCard(message)
        }
    }
}

@Preview
@Composable
fun PreviewConversation() {
    ComposeTutorialTheme {
        Conversation(SampleData.conversationSample)
    }
}

  
צפייה בתצוגה המקדימה
הסתרת התצוגה המקדימה
// ...
import androidx.compose.foundation.clickable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue

class MainActivity : ComponentActivity() {
   override fun onCreate(savedInstanceState: Bundle?) {
       super.onCreate(savedInstanceState)
       setContent {
           ComposeTutorialTheme {
               Conversation(SampleData.conversationSample)
           }
       }
   }
}

@Composable
fun MessageCard(msg: Message) {
    Row(modifier = Modifier.padding(all = 8.dp)) {
        Image(
            painter = painterResource(R.drawable.profile_picture),
            contentDescription = null,
            modifier = Modifier
                .size(40.dp)
                .clip(CircleShape)
                .border(1.5.dp, MaterialTheme.colorScheme.primary, CircleShape)
        )
        Spacer(modifier = Modifier.width(8.dp))

        // We keep track if the message is expanded or not in this
        // variable
        var isExpanded by remember { mutableStateOf(false) }

        // We toggle the isExpanded variable when we click on this Column
        Column(modifier = Modifier.clickable { isExpanded = !isExpanded }) {
            Text(
                text = msg.author,
                color = MaterialTheme.colorScheme.secondary,
                style = MaterialTheme.typography.titleSmall
            )

            Spacer(modifier = Modifier.height(4.dp))

            Surface(
                shape = MaterialTheme.shapes.medium,
                shadowElevation = 1.dp,
            ) {
                Text(
                    text = msg.body,
                    modifier = Modifier.padding(all = 4.dp),
                    // If the message is expanded, we display all its content
                    // otherwise we only display the first line
                    maxLines = if (isExpanded) Int.MAX_VALUE else 1,
                    style = MaterialTheme.typography.bodyMedium
                )
            }
        }
    }
}

  
צפייה בתצוגה המקדימה
הסתרת התצוגה המקדימה
// ...
import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.animateContentSize

@Composable
fun MessageCard(msg: Message) {
    Row(modifier = Modifier.padding(all = 8.dp)) {
        Image(
            painter = painterResource(R.drawable.profile_picture),
            contentDescription = null,
            modifier = Modifier
                .size(40.dp)
                .clip(CircleShape)
                .border(1.5.dp, MaterialTheme.colorScheme.secondary, CircleShape)
        )
        Spacer(modifier = Modifier.width(8.dp))

        // We keep track if the message is expanded or not in this
        // variable
        var isExpanded by remember { mutableStateOf(false) }
        // surfaceColor will be updated gradually from one color to the other
        val surfaceColor by animateColorAsState(
            if (isExpanded) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.surface,
        )

        // We toggle the isExpanded variable when we click on this Column
        Column(modifier = Modifier.clickable { isExpanded = !isExpanded }) {
            Text(
                text = msg.author,
                color = MaterialTheme.colorScheme.secondary,
                style = MaterialTheme.typography.titleSmall
            )

            Spacer(modifier = Modifier.height(4.dp))

            Surface(
                shape = MaterialTheme.shapes.medium,
                shadowElevation = 1.dp,
                // surfaceColor color will be changing gradually from primary to surface
                color = surfaceColor,
                // animateContentSize will change the Surface size gradually
                modifier = Modifier.animateContentSize().padding(1.dp)
            ) {
                Text(
                    text = msg.body,
                    modifier = Modifier.padding(all = 4.dp),
                    // If the message is expanded, we display all its content
                    // otherwise we only display the first line
                    maxLines = if (isExpanded) Int.MAX_VALUE else 1,
                    style = MaterialTheme.typography.bodyMedium
                )
            }
        }
    }
}

  
צפייה בתצוגה המקדימה
הסתרת התצוגה המקדימה

השלבים הבאים

כל הכבוד, סיימת את המדריך לכתיבה! יצרנו מסך פשוט לשיחה להציג ביעילות רשימה של הודעות מונפשות שמכילות תמונה טקסטים, שתוכננו באמצעות עקרונות של Material Design וכוללים עיצוב כהה תצוגות מקדימות – והכול בפחות מ-100 שורות קוד!

הנה מה שלמדתם עד עכשיו:

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

אם אתם רוצים להתעמק בחלק מהשלבים האלה, היעזרו במשאבים הבאים.

השלבים הבאים

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