الدرس 1: الدوال القابلة للتعديل
تم تصميم Jetpack Compose استنادًا إلى الدوال القابلة للإنشاء. تتيح لك هذه الدوال تحديد
واجهة مستخدم التطبيق برمجيًا من خلال وصف الشكل الذي ينبغي أن يبدو عليه وتوفير تبعيات البيانات،
بدلاً من التركيز على عملية إنشاء واجهة المستخدم (تهيئة عنصر ما،
إرفاقه بأحد الوالدين، وما إلى ذلك). لإنشاء دالة قابلة للإنشاء، ما عليك سوى إضافة
تعليق توضيحي @Composable
لاسم الدالة
إضافة عنصر نصي
للبدء، قم بتنزيل أحدث إصدار من يمكنك إنشاء تطبيق Android Studio من خلال اختيار مشروع جديد، وضمن فئة الهاتف والجهاز اللوحي، اختَر إفراغ النشاط. أدخِل اسمًا للتطبيق ComposeTutorial وانقر على إنهاء. الإعداد التلقائي يحتوي القالب بالفعل على بعض عناصر Compose، ولكن في هذا البرنامج التعليمي ستنشئه خطوة خطوة بخطوة.
أولاً، اعرض رسالة "مرحبًا بالعالم!" النص عن طريق إضافة عنصر نصي داخل
طريقة onCreate
. يمكنك القيام بذلك عن طريق تحديد محتوى
وحظره واستدعاء
Text
الدالة القابلة للإنشاء. تشير رسالة الأشكال البيانية
تحدّد قطعة setContent
تنسيق النشاط حيث
الدوال القابلة للإنشاء. لا يمكن استدعاء الدوال القابلة للإنشاء إلا من عناصر أخرى قابلة للإنشاء
الأخرى.
تستخدم Jetpack Compose مكونًا إضافيًا للمحول البرمجي بلغة Kotlin لتحويل هذه الدوال القابلة للإنشاء إلى
عناصر واجهة المستخدم الخاصة بالتطبيق. على سبيل المثال، العنصر Text
القابل للإنشاء
تعرض الدالة المحددة في مكتبة واجهة مستخدم Compose تسمية نصية على الشاشة.
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"
يتيح لك التعليق التوضيحي @Preview
معاينة الدوال القابلة للإنشاء في Android.
الاستوديو بدون الحاجة إلى إنشاء التطبيق وتثبيته على جهاز 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: التنسيقات
عناصر واجهة المستخدم تسلسلية، وتحتوي على عناصر مضمنة في عناصر أخرى. في Compose، يمكنك إنشاء تسلسل هرمي لواجهة المستخدم عن طريق استدعاء الدوال القابلة للإنشاء من الدوال الأخرى القابلة للإنشاء.
إضافة نصوص متعدّدة
لقد أنشأت حتى الآن أول دالة قابلة للإنشاء ومعاينة! استكشاف المزيد من Jetpack Compose ستنشئ شاشة مراسلة بسيطة تحتوي على قائمة بالرسائل يمكن توسيعها باستخدام بعض الرسوم المتحركة.
ابدأ بجعل الرسالة قابلة للإنشاء أكثر ثراءً من خلال عرض اسم مؤلفها
محتوى الرسالة. تحتاج أولاً إلى تغيير المعلمة القابلة للإنشاء لقبول
عنصر 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!") ) }
تُنشئ هذه التعليمة البرمجية عنصري نص داخل طريقة عرض المحتوى. ومع ذلك، نظرًا لأنك لم تقدم وأي معلومات حول كيفية ترتيبها، يتم رسم عناصر النص فوق بعضها البعض، مما يجعل النص غير قابل للقراءة.
استخدام عمود
// ... 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: التصميم متعدد الأبعاد
تم تصميم ميزة Compose لدعم مبادئ التصميم المتعدد الأبعاد. تنفذ العديد من عناصر واجهة المستخدم الخاصة بها تصميم Material Design في العلبة. في هذا الدرس، ستصمم تطبيقك باستخدام التصميم المتعدد الأبعاد التطبيقات المصغّرة.
استخدام التصميم متعدد الأبعاد
أصبح تصميم رسالتك له تنسيق الآن، ولكنه لا يبدو رائعًا حتى الآن.
يوفر Jetpack Compose تنفيذًا للتصميم المتعدد الأبعاد 3 (Material Design) وعناصر واجهة المستخدم التابعة له خارج
. سيتم تحسين مظهر "MessageCard
"
قابلة للإنشاء باستخدام تصميم متعدد الأبعاد.
للبدء، يجب إحاطة الدالة MessageCard
بالرمز
تم إنشاء مظهر Material Design في مشروعك، ComposeTutorialTheme
،
بالإضافة إلى Surface
.
نفِّذ ذلك في @Preview
وفي
setContent
. سيؤدي ذلك إلى السماح للعناصر القابلة للإنشاء
اكتساب الأنماط على النحو المحدَّد في مظهر تطبيقك، ما يضمن الاتساق في التطبيق.
صُمِّم التصميم المتعدد الأبعاد استنادًا إلى ثلاث ركائز: Color
Typography
وShape
ستتم إضافتها واحدة تلو الأخرى.
ملاحظة: ينشئ نموذج نشاط الإنشاء الفارغ مظهرًا تلقائيًا لمشروعك
تخصيص
MaterialTheme
إذا قمت بتسمية مشروعك بأي شيء مختلف عن
ComposeTutorial: يمكنك العثور على مظهرك المخصّص في
ملف 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 ) } } } }
تفعيل المظهر الداكن
المظهر الداكن (أو الوضع الليلي) لتجنب العرض الساطع خاصةً في الليل، أو ببساطة لحفظ بطارية الجهاز. بفضل توافق التصميم المتعدد الأبعاد، يمكن لـ Jetpack Compose التعامل مع العقبات المظهر تلقائيًا. إن استخدام ألوان ونصوص وخلفيات 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
العناصر القابلة للإنشاء (وأطفالها) باستخدام
ستتم إعادة رسم هذه الحالة تلقائيًا عند تعديل القيمة. وهذا ما يسمى
إعادة التركيب.
باستخدام واجهات برمجة تطبيقات حالة Compose مثل 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 ) } } } }
الخطوات التالية
تهانينا، لقد أنهيت البرنامج التعليمي حول الإنشاء! لقد أنشأت شاشة محادثة بسيطة تعرض بكفاءة قائمة تضم الرسائل القابلة للتوسيع والمتحرّكة التي تحتوي على صورة ونصوص، وقد صُمّمت بالاستناد إلى مبادئ "التصميم المتعدد الأبعاد" مع مظهر داكن مع إمكانية المعاينات، وكل ذلك أقل من 100 سطر من الرموز.
إليك ما تعلمته حتى الآن:
- تعريف الدوال المكوِّنة
- عند إضافة عناصر مختلفة إلى العنصر
- هيكلة مكون واجهة المستخدم باستخدام مواد التخطيط القابلة للتعديل
- توسيع المواد الكيميائية باستخدام مفاتيح التعديل
- إنشاء قائمة فعالة
- تتبع الحالة وتعديلها
- إضافة تفاعل المستخدم على عنصر قابل للتعديل
- الرسوم المتحركة للرسائل أثناء توسيعها
إذا كنت تريد التعمّق في بعض هذه الخطوات، اطّلِع على المراجع أدناه.