שיעור 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
. לעדכון
את התצוגות המקדימות בכל שלב, לחצו על הלחצן 'רענון' בחלק העליון של חלון התצוגה המקדימה.
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") }
שיעור 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 שורות קוד!
הנה מה שלמדתם עד עכשיו:
- הגדרת פונקציות קומפוזביליות
- הוספת אלמנטים שונים בתוכן הקומפוזבילי
- קביעת המבנה של רכיב ממשק המשתמש באמצעות תכנים קומפוזביליים לפריסה
- הרחבת תכנים קומפוזביליים באמצעות מגבילים
- יצירת רשימה יעילה
- מעקב אחר המצב ושינוי שלו
- הוספת אינטראקציה של משתמשים בתוכן קומפוזבילי
- הצגת הודעות מונפשות תוך כדי הרחבת ההודעות
אם אתם רוצים להתעמק בחלק מהשלבים האלה, היעזרו במשאבים הבאים.