1. مقدمة
في هذا الدرس التطبيقي حول الترميز، ستتعلّم كيفية تصميم التطبيقات في Jetpack Compose باستخدام التصميم Material Design 3. ستتعرف أيضًا على الكتل البرمجية الإنشائية لمخططات الألوان وأسلوب الخط والأشكال في Material Design 3، والتي تساعدك على مظهر تطبيقك بطرق مخصصة ويسهل الوصول إليها.
بالإضافة إلى ذلك، سوف تستكشف إمكانية استخدام المواضيع الديناميكية ومستويات التوكيد المختلفة.
ما سوف تتعلمه
في هذا الدرس التطبيقي حول الترميز، ستتعرَّف على ما يلي:
- الجوانب الرئيسية لموضوعات Material 3
- أنظمة ألوان Material 3 وكيفية إنشاء مظاهر لتطبيقك
- كيفية إتاحة استخدام مظاهر ديناميكية فاتحة/داكنة في تطبيقك
- أسلوب الخط والأشكال لتخصيص تطبيقك
- مكونات Material 3 وتخصيصها لتصميم تطبيقك
ما الذي ستقوم ببنائه
في هذا الدرس التطبيقي حول الترميز، ستُظهر تطبيق برنامج بريد إلكتروني باسم Reply. تبدأ بتطبيق غير نمط، باستخدام المظهر الأساسي، وستطبق ما تعلمته لوضع مظهر للتطبيق ودعم المظاهر الداكنة.
نقطة البداية التلقائية لتطبيقنا مع المظهر الأساسي.
ستنشئ المظهر باستخدام نظام الألوان وأسلوب الخط والأشكال، ثم ستطبقه على قائمة عناوين البريد الإلكتروني وصفحة التفاصيل في تطبيقك. سيكون بإمكانك أيضًا إضافة دعم المظاهر الديناميكية إلى التطبيق. في نهاية الدرس التطبيقي حول الترميز، سيصبح بإمكانك استخدام المظاهر الديناميكية والألوان في تطبيقك.
نقطة نهاية درس تطبيقي حول الترميز باستخدام ألوان فاتحة ومظاهر ديناميكية فاتحة
نقطة نهاية درس تطبيقي حول الترميز باستخدام ألوان داكنة ومظهر ديناميكي غامق
ما ستحتاجه
- استخدام أحدث إصدار من "استوديو Android"
- تجربة أساسية مع لغة Kotlin
- فهم أساسي لحزمة Jetpack Compose
- الإلمام الأساسي بتنسيقات "الكتابة"، مثل الصف والعمود والمعدّل
2. بدء الإعداد
في هذه الخطوة، يمكنك تنزيل الرمز الكامل لتطبيق Reply الذي ستقوم بتصميمه في هذا الدرس التطبيقي حول الترميز.
الحصول على الرمز
يمكن العثور على رمز هذا الدرس التطبيقي في مستودع GitHub android-compose-codelabs. لاستنساخه، قم بتشغيل:
$ git clone https://github.com/googlecodelabs/android-compose-codelabs
بدلاً من ذلك، يمكنك تنزيل ملفين مضغوطين:
الاطّلاع على نموذج التطبيق
يحتوي الرمز الذي نزّلته للتو على رمز لجميع الدروس التطبيقية المتاحة في Compose. لإكمال هذا الدرس التطبيقي حول الترميز، افتح مشروع ThemingCodelab في "استوديو Android".
ننصحك بأن تبدأ بالرمز في الفرع الرئيسي وأن تتّبع الدروس التطبيقية خطوة بخطوة بالوتيرة التي تناسبك. يمكنك في أي وقت تشغيل أي من الإصدارين في "استوديو Android" من خلال تغيير فرع المشروع.
استكشاف رمز البدء
يحتوي التعليمة البرمجية الرئيسية على حزمة واجهة مستخدم، والتي تحتوي على الحزم والملفات الرئيسية التالية التي ستتفاعل معها:
MainActivity.kt
: نشاط نقطة الدخول الذي يتم من خلاله بدء تطبيق "الرد"com.example.reply.ui.theme
– تحتوي هذه الحزمة على مظاهر وأسلوب الخط وأنظمة الألوان. ستضيف Material theming في هذه الحزمة.com.example.reply.ui.components
– يحتوي على المكوّنات المخصّصة للتطبيق، مثل عناصر القائمة وأشرطة التطبيقات وما إلى ذلك. وسيتم تطبيق مظاهر على هذه المكوّنات.ReplyApp.kt
– هذه هي دالة الدمج الرئيسية التي سيتم فيها بدء شجرة واجهة المستخدم. سيتم تطبيق مواضيع المستوى الأعلى في هذا الملف.
سيركّز هذا الدرس التطبيقي حول الترميز على ملفات حزمة ui
.
3- تصميم المادة 3
يتيح Jetpack Compose تنفيذ التصميم المتعدد الأبعاد، وهو نظام تصميم شامل لإنشاء الواجهات الرقمية. تمّ إنشاء مكوّنات التصميم المتعدد الأبعاد (الأزرار والبطاقات ومفاتيح التبديل وما إلى ذلك) بالإضافة إلى ميزة تخصيص التصميم المتعدد الأبعاد، وهي طريقة منهجية لتخصيص التصميم المتعدد الأبعاد ليعكس العلامة التجارية لمنتجك بشكل أفضل.
يضم مظهر Material 3 الأنظمة الفرعية التالية لإضافتها إلى تطبيقك: نظام الألوان وأسلوب الخط والأشكال. عند تخصيص هذه القيم، تظهر التغييرات تلقائيًا في مكوّنات M3 المستخدَمة لإنشاء تطبيقك. لنتعمق في كل نظام فرعي ونطبقه في نموذج التطبيق.
نظام Material 3 الفرعي من الألوان وأسلوب الخط والأشكال.
4. الألوان
يعتمد نظام الألوان على مجموعة من خمسة ألوان أساسية يرتبط كل منها بلوحة ألوان مكوَّنة من 13 لونًا تستخدمها مكونات المادة 3.
خمسة ألوان أساسية لإنشاء مظاهر M3:
يتم بعد ذلك توفير كل لون تمييز (أساسي وثانوي وثالث) بأربعة ألوان متوافقة من درجات مختلفة للإقران، وتحديد التوكيد، والتعبير المرئي.
أربعة ألوان من ألوان التمييز الأساسية والثانوية والثالثة:
وبالمثل، يتم تقسيم الألوان المحايدة إلى أربع درجات لونية متوافقة تستخدم للأسطح والخلفية. من المهم أيضًا التأكيد على أيقونات النص عند وضعها على أي سطح.
أربعة ألوان من درجات اللون المحايدة الأساسية:
يمكنك الاطّلاع على مزيد من المعلومات عن أدوار الألوان ونظام الألوان.
جارٍ إنشاء أنظمة الألوان
على الرغم من أنّه يمكنك إنشاء رمز ColorScheme
مخصّص يدويًا، يسهل غالبًا إنشاء رمز باستخدام ألوان المصدر من علامتك التجارية. تتيح لك أداة إنشاء نسق المواد إجراء ذلك، ويمكنك تصدير رموز إنشاء المظاهر اختياريًا.
يمكنك اختيار أي لون تريده، ولكن في حالة الاستخدام، ستستخدم اللون الأساسي التلقائي للردّ #825500
. انقر على اللون الأساسي في قسم الألوان الأساسية الأيمن وأضِف الرمز في منتقي الألوان.
إضافة رمز اللون الأساسي في Material Theme Builder.
بمجرد إضافة اللون الأساسي في Material Theme Builder، من المفترض أن يظهر لك المظهر التالي وخيار التصدير في أعلى الجانب الأيسر. في هذا الدرس التطبيقي حول الترميز، يمكنك تصدير المظهر في Jetpack Compose.
يمكنك استخدام أداة Material Theme Builder، التي يتوفّر لها خيار تصدير البيانات في أعلى يسار الصفحة.
ينشئ اللون الأساسي #825500
المظهر التالي الذي ستضيفه إلى التطبيق. توفّر المادة 3 مجموعة كبيرة من أدوار الألوان للتعبير بمرونة عن حالة المكوّن وبروزه وتوكيده.
تم تصدير الألوان الفاتحة والداكنة من اللون الأساسي.
يحتوي الملف الذي تم إنشاؤه من قِبل "The Color.kt
" على ألوان مظهرك وجميع الأدوار المحدّدة لكل من الألوان الفاتحة والداكنة.
Color.kt
package com.example.reply.ui.theme
import androidx.compose.ui.graphics.Color
val md_theme_light_primary = Color(0xFF825500)
val md_theme_light_onPrimary = Color(0xFFFFFFFF)
val md_theme_light_primaryContainer = Color(0xFFFFDDB3)
val md_theme_light_onPrimaryContainer = Color(0xFF291800)
val md_theme_light_secondary = Color(0xFF6F5B40)
val md_theme_light_onSecondary = Color(0xFFFFFFFF)
val md_theme_light_secondaryContainer = Color(0xFFFBDEBC)
val md_theme_light_onSecondaryContainer = Color(0xFF271904)
val md_theme_light_tertiary = Color(0xFF51643F)
val md_theme_light_onTertiary = Color(0xFFFFFFFF)
val md_theme_light_tertiaryContainer = Color(0xFFD4EABB)
val md_theme_light_onTertiaryContainer = Color(0xFF102004)
val md_theme_light_error = Color(0xFFBA1A1A)
val md_theme_light_errorContainer = Color(0xFFFFDAD6)
val md_theme_light_onError = Color(0xFFFFFFFF)
val md_theme_light_onErrorContainer = Color(0xFF410002)
val md_theme_light_background = Color(0xFFFFFBFF)
val md_theme_light_onBackground = Color(0xFF1F1B16)
val md_theme_light_surface = Color(0xFFFFFBFF)
val md_theme_light_onSurface = Color(0xFF1F1B16)
val md_theme_light_surfaceVariant = Color(0xFFF0E0CF)
val md_theme_light_onSurfaceVariant = Color(0xFF4F4539)
val md_theme_light_outline = Color(0xFF817567)
val md_theme_light_inverseOnSurface = Color(0xFFF9EFE7)
val md_theme_light_inverseSurface = Color(0xFF34302A)
val md_theme_light_inversePrimary = Color(0xFFFFB951)
val md_theme_light_shadow = Color(0xFF000000)
val md_theme_light_surfaceTint = Color(0xFF825500)
val md_theme_light_outlineVariant = Color(0xFFD3C4B4)
val md_theme_light_scrim = Color(0xFF000000)
val md_theme_dark_primary = Color(0xFFFFB951)
val md_theme_dark_onPrimary = Color(0xFF452B00)
val md_theme_dark_primaryContainer = Color(0xFF633F00)
val md_theme_dark_onPrimaryContainer = Color(0xFFFFDDB3)
val md_theme_dark_secondary = Color(0xFFDDC2A1)
val md_theme_dark_onSecondary = Color(0xFF3E2D16)
val md_theme_dark_secondaryContainer = Color(0xFF56442A)
val md_theme_dark_onSecondaryContainer = Color(0xFFFBDEBC)
val md_theme_dark_tertiary = Color(0xFFB8CEA1)
val md_theme_dark_onTertiary = Color(0xFF243515)
val md_theme_dark_tertiaryContainer = Color(0xFF3A4C2A)
val md_theme_dark_onTertiaryContainer = Color(0xFFD4EABB)
val md_theme_dark_error = Color(0xFFFFB4AB)
val md_theme_dark_errorContainer = Color(0xFF93000A)
val md_theme_dark_onError = Color(0xFF690005)
val md_theme_dark_onErrorContainer = Color(0xFFFFDAD6)
val md_theme_dark_background = Color(0xFF1F1B16)
val md_theme_dark_onBackground = Color(0xFFEAE1D9)
val md_theme_dark_surface = Color(0xFF1F1B16)
val md_theme_dark_onSurface = Color(0xFFEAE1D9)
val md_theme_dark_surfaceVariant = Color(0xFF4F4539)
val md_theme_dark_onSurfaceVariant = Color(0xFFD3C4B4)
val md_theme_dark_outline = Color(0xFF9C8F80)
val md_theme_dark_inverseOnSurface = Color(0xFF1F1B16)
val md_theme_dark_inverseSurface = Color(0xFFEAE1D9)
val md_theme_dark_inversePrimary = Color(0xFF825500)
val md_theme_dark_shadow = Color(0xFF000000)
val md_theme_dark_surfaceTint = Color(0xFFFFB951)
val md_theme_dark_outlineVariant = Color(0xFF4F4539)
val md_theme_dark_scrim = Color(0xFF000000)
val seed = Color(0xFF825500)
يحتوي ملف واحد (The Theme.kt
) تم إنشاؤه على إعداد للألوان الفاتحة والداكنة ومظهر التطبيق. ويتضمّن أيضًا دالة إنشاء الموضوع الرئيسية، AppTheme()
.
Theme.kt
package com.example.reply.ui.theme
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.material3.darkColorScheme
import androidx.compose.runtime.Composable
private val LightColors = lightColorScheme(
primary = md_theme_light_primary,
onPrimary = md_theme_light_onPrimary,
primaryContainer = md_theme_light_primaryContainer,
onPrimaryContainer = md_theme_light_onPrimaryContainer,
secondary = md_theme_light_secondary,
onSecondary = md_theme_light_onSecondary,
secondaryContainer = md_theme_light_secondaryContainer,
onSecondaryContainer = md_theme_light_onSecondaryContainer,
tertiary = md_theme_light_tertiary,
onTertiary = md_theme_light_onTertiary,
tertiaryContainer = md_theme_light_tertiaryContainer,
onTertiaryContainer = md_theme_light_onTertiaryContainer,
error = md_theme_light_error,
errorContainer = md_theme_light_errorContainer,
onError = md_theme_light_onError,
onErrorContainer = md_theme_light_onErrorContainer,
background = md_theme_light_background,
onBackground = md_theme_light_onBackground,
surface = md_theme_light_surface,
onSurface = md_theme_light_onSurface,
surfaceVariant = md_theme_light_surfaceVariant,
onSurfaceVariant = md_theme_light_onSurfaceVariant,
outline = md_theme_light_outline,
inverseOnSurface = md_theme_light_inverseOnSurface,
inverseSurface = md_theme_light_inverseSurface,
inversePrimary = md_theme_light_inversePrimary,
surfaceTint = md_theme_light_surfaceTint,
outlineVariant = md_theme_light_outlineVariant,
scrim = md_theme_light_scrim,
)
private val DarkColors = darkColorScheme(
primary = md_theme_dark_primary,
onPrimary = md_theme_dark_onPrimary,
primaryContainer = md_theme_dark_primaryContainer,
onPrimaryContainer = md_theme_dark_onPrimaryContainer,
secondary = md_theme_dark_secondary,
onSecondary = md_theme_dark_onSecondary,
secondaryContainer = md_theme_dark_secondaryContainer,
onSecondaryContainer = md_theme_dark_onSecondaryContainer,
tertiary = md_theme_dark_tertiary,
onTertiary = md_theme_dark_onTertiary,
tertiaryContainer = md_theme_dark_tertiaryContainer,
onTertiaryContainer = md_theme_dark_onTertiaryContainer,
error = md_theme_dark_error,
errorContainer = md_theme_dark_errorContainer,
onError = md_theme_dark_onError,
onErrorContainer = md_theme_dark_onErrorContainer,
background = md_theme_dark_background,
onBackground = md_theme_dark_onBackground,
surface = md_theme_dark_surface,
onSurface = md_theme_dark_onSurface,
surfaceVariant = md_theme_dark_surfaceVariant,
onSurfaceVariant = md_theme_dark_onSurfaceVariant,
outline = md_theme_dark_outline,
inverseOnSurface = md_theme_dark_inverseOnSurface,
inverseSurface = md_theme_dark_inverseSurface,
inversePrimary = md_theme_dark_inversePrimary,
surfaceTint = md_theme_dark_surfaceTint,
outlineVariant = md_theme_dark_outlineVariant,
scrim = md_theme_dark_scrim,
)
@Composable
fun AppTheme(
useDarkTheme: Boolean = isSystemInDarkTheme(),
content: @Composable() () -> Unit
) {
val colors = if (!useDarkTheme) {
LightColors
} else {
DarkColors
}
MaterialTheme(
colorScheme = colors,
content = content
)
}
إنّ العنصر الأساسي لتنفيذها في Jetpack Compose هو عنصر MaterialTheme
القابل للإنشاء.
يمكنك التفاف MaterialTheme()
القابلة للإنشاء في الدالة AppTheme()
، والتي تستخدم معلمتَين:
useDarkTheme
: ترتبط هذه المَعلمة بالدالةisSystemInDarkTheme()
لمراقبة إعدادات مواضيع النظام وتطبيق المظهر الفاتح أو الداكن. وإذا كنت تريد إبقاء تطبيقك بمظهر داكن أو فاتح اللون يدويًا، يمكنك ضبط قيمة منطقية إلىuseDarkTheme
.content
- المحتوى الذي سيتم تطبيق المظهر عليه
Theme.kt
@Composable
fun AppTheme(
useDarkTheme: Boolean = isSystemInDarkTheme(),
content: @Composable() () -> Unit
) {
val colors = if (!useDarkTheme) {
LightColors
} else {
DarkColors
}
MaterialTheme(
colorScheme = colors,
content = content
)
}
إذا حاولت تشغيل التطبيق الآن، من المفترض أن يظهر بالشكل نفسه. على الرغم من استيراد نظام الألوان الجديد بألوان مظاهر جديدة، لا يزال بإمكانك رؤية المظاهر الأساسية لأنك لم تطبق المظهر على تطبيق Compose.
التطبيق يتضمن مواضيع أساسية في حال عدم تطبيق أي مظهر
لتطبيق المظهر الجديد، في MainActivity.kt
، عليك التفاف عنصر ReplyApp
الرئيسي القابل للإنشاء مع دالة الموضوع الرئيسية AppTheme()
.
MainActivity.kt
setContent {
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
AppTheme {
ReplyApp(/*..*/)
}
}
ويمكنك أيضًا تحديث وظائف المعاينة لرؤية المظهر الذي تم تطبيقه على معاينات التطبيق. التفاف ReplyApp
القابلة للإنشاء داخل ReplyAppPreview()
مع AppTheme
لتطبيقها على المعاينات.
لديك مظهرا النظام الفاتح والداكن محدّدان في مَعلمات المعاينة، لذا سترى كل من المعاينة.
MainActivity.kt
@Preview(
uiMode = Configuration.UI_MODE_NIGHT_YES,
name = "DefaultPreviewDark"
)
@Preview(
uiMode = Configuration.UI_MODE_NIGHT_NO,
name = "DefaultPreviewLight"
)
@Composable
fun ReplyAppPreview() {
AppTheme {
ReplyApp(
replyHomeUIState = ReplyHomeUIState(
emails = LocalEmailsDataProvider.allEmails
)
)
}
}
في حال تشغيل التطبيق الآن، من المفترض أن تظهر لك معاينات التطبيق بألوان المظاهر التي تم استيرادها بدلاً من المظهر الأساسي.
تطبيق بمظهر أساسي (على اليسار)
تطبيق بمظهر الألوان الذي تم استيراده (يمين).
معاينات التطبيقات الفاتحة والداكنة مع مظاهر الألوان التي تم استيرادها
تتوافق المادة 3 مع نظام الألوان الفاتحة والداكنة. أنك جمعت التطبيق بالمظهر الذي تم استيراده فقط؛ تستخدم مكونات المادة 3 أدوار الألوان التلقائية.
لنتعرَّف على معلومات عن أدوار الألوان واستخدامها قبل البدء في إضافتها إلى التطبيق.
أدوار الألوان وإمكانية الوصول
يمكن استخدام كل دور لوني في مجموعة متنوعة من الأماكن اعتمادًا على حالة المكوِّن وبروزه وتركيزه.
أدوار الألوان للألوان الأساسية والثانوية والثلاثية.
الأساسي هو اللون الأساسي الذي يُستخدم للمكوّنات الرئيسية مثل الأزرار البارزة والحالات النشطة.
يتم استخدام لون المفتاح الثانوي للمكوّنات الأقل بروزًا في واجهة المستخدم، مثل شرائح الفلاتر.
ويتم استخدام اللون الرئيسي الثالث لتوفير لمسات متباينة، واستخدام ألوان محايدة للخلفية والأسطح في التطبيق.
يوفّر نظام ألوان المواد قيمًا لدرجات اللون وقياسات قياسية يمكن استخدامها لتلبية نسب التباين التي يمكن الوصول إليها. يمكنك استخدام القيم الأساسية في أعلى الحاوية الأساسية، وفي الحاوية الأساسية فوق الحاوية الأساسية، ونفسها مع غيرها من ألوان التمييز والألوان المحايدة لتوفير تباين يمكن للمستخدم الوصول إليه.
لمزيد من المعلومات، يُرجى الاطّلاع على أدوار الألوان وإمكانية الوصول.
ارتفاعات الدرجات اللونية والظل
تمثل المادة 3 المسقط الرأسي باستخدام تراكبات ألوان الدرجات اللونية بشكل أساسي. تعد هذه طريقة جديدة للتمييز بين الحاويات والأسطح من بعضها البعض، مع زيادة ارتفاع درجات اللون، تستخدم درجات لونية أكثر بروزًا، بالإضافة إلى الظلال.
ارتفاع درجة اللون في المستوى 2 والذي يأخذ اللون من خانة اللون الأساسية.
تم أيضًا تغيير تراكبات الارتفاع في المظاهر الداكنة إلى تراكبات ألوان الدرجات اللونية في Material Design 3. يأتي لون التراكب من فتحة اللون الأساسية.
يشمل سطح M3، الجزء الخلفي الذي يمكن تكوينه خلف معظم مكونات M3، دعمًا لارتفاع الدرجات اللونية والظل:
Surface(
modifier = modifier,
tonalElevation = {..}
shadowElevation = {..}
) {
Column(content = content)
}
إضافة الألوان إلى التطبيق
في حال تشغيل التطبيق، يمكنك رؤية الألوان التي تم تصديرها في التطبيق حيث تظهر المكوّنات بألوان تلقائية. الآن بعد أن عرفنا أدوار الألوان واستخدامها، لنجعل التطبيق مظهرًا لأدوار الألوان الصحيحة.
تطبيق بمظهر الألوان ومكوّنات تتولى أدوار الألوان التلقائية
ألوان السطح
في الشاشة الرئيسية، ستبدأ بالتفاف التطبيق الرئيسي القابل للإنشاء في Surface()
لتوفير القاعدة لوضع محتوى التطبيق فوقه. افتح MainActivity.kt
ويلتفّ عنصر ReplyApp()
القابل للإنشاء باستخدام Surface
.
ستقدم أيضًا ارتفاعًا تدرّجيًا يبلغ 5.dp لمنح السطح لونًا لونيًا للخانة الأساسية، ما يساعد في توفير التباين مقابل عنصر القائمة وشريط البحث أعلاه. يكون ارتفاع درجة اللون والظل للسطح تلقائيًا 0.dp.
MainActivity.kt
AppTheme {
Surface(tonalElevation = 5.dp) {
ReplyApp(
replyHomeUIState = uiState,
// other parameters
)
}
}
إذا قمت بتشغيل تطبيقك الآن ورأيت صفحة "القائمة" و"التفاصيل"، يُفترض أن ترى سطح الدرجات اللونية مطبقًا على التطبيق بأكمله.
خلفية التطبيق بدون سطح ولون اللون (على اليسار)
خلفية التطبيق مع تطبيق السطح واللون اللوني (على اليمين)
ألوان شريط التطبيق
ليس لشريط البحث المخصص في الأعلى خلفية واضحة مثل طلبات التصميم. ويتم تلقائيًا ضبطه على سطح القاعدة التلقائي. يمكنك توفير خلفية الفصل بين الصور بشكل واضح.
شريط بحث مخصّص بدون خلفية (اليسار)
شريط بحث مخصّص مع خلفية (إلى اليمين)
ستتمكن الآن من تعديل تطبيق ui/components/ReplyAppBars.kt
، الذي يحتوي على شريط التطبيقات. ستتم إضافة MaterialTheme.colorScheme.background
إلى Modifier
الخاص بـ Row
القابلة للتعديل.
ReplyAppBars.kt
@Composable
fun ReplySearchBar(modifier: Modifier = Modifier) {
Row(
modifier = modifier
.fillMaxWidth()
.padding(16.dp)
.background(MaterialTheme.colorScheme.background),
verticalAlignment = Alignment.CenterVertically
) {
// Search bar content
}
}
يُفترض أن يظهر الآن فصل واضح بين سطح الدرجات اللونية وشريط التطبيق بلون الخلفية.
شريط البحث الذي يظهر لون الخلفية فوق سطح درجات اللون
ألوان زر الإجراءات العائمة
زر الإجراء الرئيسي (FAB) كبير بدون تطبيق أي مواضيع (لليسار).
زر الإجراء الرئيسي (FAB) كبير الحجم بمظهر مع لون ثالث (يمين).
على الشاشة الرئيسية، يمكنك تحسين مظهر زر الإجراء الرئيسي (FAB) بحيث يظهر كزر لعبارة الحث على اتّخاذ إجراء. لتنفيذ ذلك، يتم استخدام لون تمييز ثالث لها.
في ملف ReplyListContent.kt
، عدِّل containerColor
للعنصر الرئيسي (FAB) إلى tertiaryContainer
ولون المحتوى إلى onTertiaryContainer
للحفاظ على إمكانية الوصول وتباين الألوان.
ReplyListContent.kt
ReplyInboxScreen(/*..*/) {
// Email list content
LargeFloatingActionButton(
containerColor = MaterialTheme.colorScheme.tertiaryContainer,
contentColor = MaterialTheme.colorScheme.onTertiaryContainer
){
/*..*/
}
}
يمكنك تشغيل التطبيق للاطّلاع على مظهر زر الإجراء الرئيسي (FAB). أنت تستخدم LargeFloatingActionButton
في هذا الدرس التطبيقي حول الترميز.
ألوان البطاقة
تستخدم قائمة عناوين البريد الإلكتروني على الشاشة الرئيسية مكون بطاقة. تكون هذه الطريقة بطاقة معبأة تستخدم لون خيار السطح للون الحاوية لتوفير فصل واضح بين لون السطح ولون البطاقة. يوفر Compose أيضًا إمكانية تنفيذ ElevatedCard
وOutlinedCard
.
يمكنك تمييز بعض العناصر المهمة بشكل أكبر من خلال توفير درجات ألوان ثانوية. يمكنك تعديل ui/components/ReplyEmailListItem.kt
من خلال تعديل لون حاوية البطاقة باستخدام CardDefaults.cardColors()
للرسائل الإلكترونية المهمة:
ReplyEmailListItem.kt
Card(
modifier = modifier
.padding(horizontal = 16.dp, vertical = 4.dp)
.semantics { selected = isSelected }
.clickable { navigateToDetail(email.id) },
colors = CardDefaults.cardColors(
containerColor = if (email.isImportant)
MaterialTheme.colorScheme.secondaryContainer
else MaterialTheme.colorScheme.surfaceVariant
)
){
/*..*/
}
ميِّز عنصر القائمة باستخدام لون الحاوية الثانوي على سطح درجات اللون.
لون عنصر قائمة التفاصيل
الآن، لقد انتهيت من تصميم شاشتك الرئيسية. يمكنك إلقاء نظرة على صفحة التفاصيل من خلال النقر على أي من عناصر قائمة عناوين البريد الإلكتروني.
صفحة التفاصيل التلقائية بدون عنصر قائمة حسب الموضوع (على اليسار)
عنصر قائمة التفاصيل مع تطبيق مظهر الخلفية (على اليمين).
لا يتم تطبيق أي لون على عنصر القائمة، لذلك يتم استخدام لون السطح التلقائي. سيتم تطبيق لون الخلفية على عنصر القائمة لإنشاء فصل وإضافة مساحة متروكة لتوفير مسافات حول الخلفية.
ReplyEmailThreadItem.kt
@Composable
fun ReplyEmailThreadItem(
email: Email,
modifier: Modifier = Modifier
) {
Column(
modifier = modifier
.fillMaxWidth()
.padding(16.dp)
.background(MaterialTheme.colorScheme.background)
.padding(20.dp)
) {
// List item content
}
}
يمكنك أن ترى أنه، فقط من خلال توفير الخلفية، يكون لديك فصل واضح بين سطح الدرجات اللونية وعنصر القائمة.
لديك الآن كل من الصفحة الرئيسية وصفحة التفاصيل باستخدام الأدوار واستخدام الألوان الصحيحة . لنرَ كيف يمكن لتطبيقك الاستفادة من الألوان الديناميكية لتوفير تجربة أكثر تخصيصًا وتماسكًا.
5- إضافة ألوان ديناميكية في التطبيق
اللون الديناميكي هو الجزء الأساسي من المادة 3، حيث تستمد الخوارزمية ألوانًا مخصّصة من خلفية المستخدم لتطبيقها على التطبيقات وواجهة مستخدم النظام.
تجعل المواضيع الديناميكية تطبيقاتك أكثر تخصيصًا. ويوفّر أيضًا للمستخدمين تجربة متّسقة وسلسة مع مظهر النظام.
تتوفّر الألوان الديناميكية على نظام التشغيل Android 12 والإصدارات الأحدث. إذا كان اللون الديناميكي متاحًا، يمكنك إعداد ألوان ديناميكية باستخدام dynamicDarkColorScheme()
أو dynamicLightColorScheme()
. وفي حال عدم تفعيلها، عليك العودة إلى استخدام ColorScheme
إضاءة أو داكنة بشكل تلقائي.
استبدِل رمز الدالة AppTheme
في ملف Theme.kt
بالرمز التالي:
Theme.kt
@Composable
fun AppTheme(
useDarkTheme: Boolean = isSystemInDarkTheme(),
content: @Composable () -> Unit
) {
val context = LocalContext.current
val colors = when {
(Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) -> {
if (useDarkTheme) dynamicDarkColorScheme(context)
else dynamicLightColorScheme(context)
}
useDarkTheme -> DarkColors
else -> LightColors
}
MaterialTheme(
colorScheme = colors,
content = content
)
}
مظهر ديناميكي مأخوذ من خلفية Android 13.
عند تشغيل التطبيق الآن، من المفترض أن يتم تطبيق المواضيع الديناميكية باستخدام الخلفية التلقائية لنظام التشغيل Android 13.
وقد تحتاج أيضًا إلى تغيير نمط شريط الحالة ديناميكيًا اعتمادًا على نظام الألوان المستخدم لتصميم تطبيقك.
تم تطبيق لون التطبيق بدون شريط الحالة (السماعة اليسرى).
تم تطبيق لون شريط الحالة على التطبيق (إلى اليمين).
لتعديل لون شريط الحالة بناءً على اللون الأساسي لمظهرك، أضِف لون شريط الحالة بعد اختيار الألوان في عنصر AppTheme
القابل للإنشاء:
Theme.kt
@Composable
fun AppTheme(
useDarkTheme: Boolean = isSystemInDarkTheme(),
content: @Composable () -> Unit
) {
// color scheme selection code
// Add primary status bar color from chosen color scheme.
val view = LocalView.current
if (!view.isInEditMode) {
SideEffect {
val window = (view.context as Activity).window
window.statusBarColor = colors.primary.toArgb()
WindowCompat
.getInsetsController(window, view)
.isAppearanceLightStatusBars = useDarkTheme
}
}
MaterialTheme(
colorScheme = colors,
content = content
)
}
عند تشغيل التطبيق، من المفترض أن يظهر شريط الحالة بألوانه الأساسية. يمكنك أيضًا تجربة المظهرَين الديناميكي الفاتح والداكن من خلال تغيير المظهر الداكن للنظام.
تم تطبيق المظهرَين الفاتح والداكن (اليسار) والداكن (اليمين) مع الخلفية التلقائية في Android 13.
حتى الآن، تم تطبيق ألوان على تطبيقك ساهمت في تحسين شكل التطبيق. ومع ذلك، يمكنك ملاحظة أن كل النص في التطبيق بنفس الحجم، لذا يمكنك الآن إضافة أسلوب الخط إلى التطبيق.
6- فن الطباعة
يحدد التصميم المتعدد الأبعاد 3 مقياس النوع. وقد تم تبسيط التسمية والتجميع لـ: العرض، والعنوان، والعنوان، والنص الأساسي، والتصنيف، مع استخدام أحجام كبيرة ومتوسطة وصغيرة لكل منها.
مقياس نوع المادة 3.
تعريف أسلوب الخط
توفِّر ميزة Compose لفئة M3 Typography
، بالإضافة إلى فئات TextStyle
وfont-related
الحالية، نموذجًا لمقياس النوع Material 3.
تقدم الدالة الإنشائية لأسلوب الخط إعدادات افتراضية لكل نمط حتى تتمكن من حذف أي معلمات لا تريد تخصيصها. لمزيد من المعلومات، يمكنك الاطّلاع على أنماط أسلوب الخط وقيمها التلقائية.
ستستخدم خمسة أنماط لأسلوب الخط في تطبيقك: headlineSmall
وtitleLarge
وbodyLarge
وbodyMedium
وlabelMedium
. ستغطي هذه الأنماط كلاً من الشاشة الرئيسية وشاشة التفاصيل.
شاشة تعرض استخدام أسلوب الخط للعنوان والتصنيف ونمط النص الأساسي.
بعد ذلك، انتقِل إلى حزمة ui/theme
وافتح Type.kt
. أضِف الرمز التالي لتقديم التنفيذ الخاص بك لبعض أنماط النص بدلاً من القيم التلقائية:
Type.kt
val typography = Typography(
headlineSmall = TextStyle(
fontWeight = FontWeight.SemiBold,
fontSize = 24.sp,
lineHeight = 32.sp,
letterSpacing = 0.sp
),
titleLarge = TextStyle(
fontWeight = FontWeight.Normal,
fontSize = 18.sp,
lineHeight = 28.sp,
letterSpacing = 0.sp
),
bodyLarge = TextStyle(
fontWeight = FontWeight.Normal,
fontSize = 16.sp,
lineHeight = 24.sp,
letterSpacing = 0.15.sp
),
bodyMedium = TextStyle(
fontWeight = FontWeight.Medium,
fontSize = 14.sp,
lineHeight = 20.sp,
letterSpacing = 0.25.sp
),
labelMedium = TextStyle(
fontWeight = FontWeight.SemiBold,
fontSize = 12.sp,
lineHeight = 16.sp,
letterSpacing = 0.5.sp
)
)
تم تحديد أسلوب الخط الآن. لإضافتها إلى المظهر، مرِّره إلى عنصر MaterialTheme()
القابل للإنشاء داخل AppTheme
:
Theme.kt
@Composable
fun AppTheme(
useDarkTheme: Boolean = isSystemInDarkTheme(),
content: @Composable() () -> Unit
) {
// dynamic theming content
MaterialTheme(
colorScheme = colors,
typography = typography,
content = content
)
}
العمل على أسلوب الخط
تمامًا مثل الألوان، ستصل إلى نمط أسلوب الخط للمظهر الحالي باستخدام MaterialTheme.typography
. يمنحك هذا مثيل أسلوب الخط لاستخدام أسلوب الخط المحدّد في Type.k
.
Text(
text = "Hello M3 theming",
style = MaterialTheme.typography.titleLarge
)
Text(
text = "you are learning typography",
style = MaterialTheme.typography.bodyMedium
)
من المحتمل ألا يحتاج منتجك إلى جميع الأنماط الافتراضية الخمسة عشر من مقياس النوع "تصميم متعدد الأبعاد". في هذا الدرس التطبيقي حول الترميز، يتم اختيار خمسة أحجام بينما يتم حذف الباقي.
بما أنّك لم تطبّق أسلوب الخط على العناصر القابلة للإنشاء Text(
، سيتم تلقائيًا الرجوع إلى Typography.bodyLarge
.
أسلوب الخط في القائمة الرئيسية
بعد ذلك، طبِّق أسلوب الخط على الدالة ReplyEmailListItem
في ui/components/ReplyEmailListItem.kt
للتمييز بين العناوين والتصنيفات:
ReplyEmailListItem.kt
Text(
text = email.sender.firstName,
style = MaterialTheme.typography.labelMedium
)
Text(
text = email.createdAt,
style = MaterialTheme.typography.labelMedium
)
Text(
text = email.subject,
style = MaterialTheme.typography.titleLarge,
modifier = Modifier.padding(top = 12.dp, bottom = 8.dp),
)
Text(
text = email.body,
maxLines = 2,
style = MaterialTheme.typography.bodyLarge,
overflow = TextOverflow.Ellipsis
)
تم تطبيق نمط الخط على الشاشة الرئيسية (اليسرى).
الشاشة الرئيسية مع تطبيق أسلوب الخط (اليمين)
أسلوب الخط في قائمة التفاصيل
وبالمثل، ستضيف أسلوب الخط في شاشة التفاصيل من خلال تعديل كل النصوص القابلة للإنشاء من ReplyEmailThreadItem
في ui/components/ReplyEmailThreadItem.kt
:
ReplyEmailThreadItem.kt
Text(
text = email.sender.firstName,
style = MaterialTheme.typography.labelMedium
)
Text(
text = stringResource(id = R.string.twenty_mins_ago),
style = MaterialTheme.typography.labelMedium
)
Text(
text = email.subject,
style = MaterialTheme.typography.bodyMedium,
modifier = Modifier.padding(top = 12.dp, bottom = 8.dp),
)
Text(
text = email.body,
style = MaterialTheme.typography.bodyLarge,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
تم تطبيق شاشة التفاصيل بدون أسلوب الخط (على اليسار).
شاشة التفاصيل مع تطبيق أسلوب الخط (اليمين)
تخصيص أسلوب الخط
من خلال ميزة "الكتابة"، من السهل جدًا تخصيص نمط النص أو توفير خط مخصّص. يمكنك تعديل TextStyle
لتخصيص نوع الخط ومجموعة الخطوط وتباعد الأحرف وما إلى ذلك.
سيتم تغيير نمط النص في ملف theme/Type.kt
، وسيتم تطبيقه على كل المكوّنات التي تستخدمه.
عدِّل fontWeight
إلى SemiBold
ومن lineHeight
إلى 32.sp
للسمة titleLarge
، حيث يتم استخدام هذا الإعداد للموضوع في عنصر القائمة. سيركز بشكل أكبر على الموضوع ويوفر فواصل واضحة.
Type.kt
...
titleLarge = TextStyle(
fontWeight = FontWeight.SemiBold,
fontSize = 18.sp,
lineHeight = 32.sp,
letterSpacing = 0.0.sp
),
...
تطبيق أسلوب الخط المخصّص على نص الموضوع:
7. الأشكال
يمكن عرض الأسطح المادية بأشكال مختلفة. أشكال الانتباه المباشر، وتحديد المكونات، وتوصيل الحالة، والتعبير عن العلامة التجارية.
تحديد الأشكال
توفِّر ميزة Compose لفئة Shapes
مَعلمات موسّعة لتنفيذ أشكال M3 الجديدة. يشبه مقياس الشكل M3، الذي يشبه مقياس الكتابة، نطاقًا معبرًا من الأشكال في واجهة المستخدم.
هناك أحجام مختلفة للأشكال في مقياس الشكل:
- صغير جدًا
- صغير
- متوسطة
- كبير
- كبير جدًا
بشكل افتراضي، يكون لكل شكل قيمة افتراضية يمكن تجاوزها. بالنسبة إلى تطبيقك، ستستخدم الشكل المتوسط لتعديل عنصر القائمة، ولكن يمكنك الإعلان عن أشكال أخرى أيضًا. أنشئ ملفًا جديدًا باسم Shape.kt
في حزمة ui/theme
وأضف الرمز للأشكال:
Shape.kt
package com.example.reply.ui.theme
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Shapes
import androidx.compose.ui.unit.dp
val shapes = Shapes(
extraSmall = RoundedCornerShape(4.dp),
small = RoundedCornerShape(8.dp),
medium = RoundedCornerShape(16.dp),
large = RoundedCornerShape(24.dp),
extraLarge = RoundedCornerShape(32.dp)
)
الآن بعد أن حددت shapes
، مرره إلى M3 MaterialTheme
كما فعلت مع الألوان وأسلوب الخط:
Theme.kt
@Composable
fun AppTheme(
useDarkTheme: Boolean = isSystemInDarkTheme(),
content: @Composable() () -> Unit
) {
// dynamic theming content
MaterialTheme(
colorScheme = colors,
typography = typography,
shapes = shapes
content = content
)
}
التعامل مع الأشكال
تمامًا كما هو الحال مع اللون وأسلوب الخط، يمكنك تطبيق الأشكال على مكونات Material باستخدام MaterialTheme.shape
، والذي يمنحك مثيل Shape
للوصول إلى أشكال Material.
العديد من مكونات Material لديها بالفعل أشكال افتراضية مطبقة عليها، ولكن يمكنك توفير الأشكال الخاصة بك وتطبيقها على المكونات عبر الفتحات المتاحة.
Card(shape = MaterialTheme.shapes.medium) { /* card content */ }
FloatingActionButton(shape = MaterialTheme.shapes.large) { /* fab content */}
تعيين مكونات Material باستخدام أنواع مختلفة من الأشكال.
يمكنك الاطلاع على تعيين الأشكال لجميع المكونات في مستندات الشكل.
هناك شكلان آخران متاحون للاستخدام: RectangleShape
وCircleShape
، وهما جزءان من ميزة Compose. لا يحتوي شكل المستطيل على نصف قطر حدي، بينما يُظهر شكل الدائرة حواف مدورة بالكامل.
يمكنك أيضًا تطبيق الأشكال على المكوّنات باستخدام Modifiers
التي تتخذ أشكالاً، مثل Modifier.clip
وModifier.background وModifier.border
.
شكل شريط التطبيق
نريد أن يكون لشريط التطبيق خلفية مستديرة بزاوية:
يستخدم TopAppBar
عنصر Row
مع لون خلفية. لعرض الخلفية المستديرة، حدِّد شكل الخلفية من خلال تمرير CircleShape
إلى أداة تعديل الخلفية:
ReplyAppBars.kt
@Composable
fun ReplySearchBar(modifier: Modifier = Modifier) {
Row(
modifier = modifier
.fillMaxWidth()
.padding(16.dp)
.background(
MaterialTheme.colorScheme.background,
CircleShape
),
verticalAlignment = Alignment.CenterVertically
) {
// Search bar content
}
}
شكل عنصر قائمة التفاصيل
أنت تستخدم على الشاشة الرئيسية بطاقة تستخدم Shape.Medium
بشكل تلقائي. ومع ذلك، بالنسبة لصفحة التفاصيل لدينا، استخدمت عمودًا بلون الخلفية بدلاً من ذلك. للحصول على مظهر موحّد للقائمة، ضع شكلاً متوسطًا عليها.
عمود عنصر قائمة التفاصيل بدون شكل في عنصر القائمة (الأيسر) وشكل متوسط في القائمة (اليمين).
ReplyEmailThreadItem.kt
@Composable
fun ReplyEmailThreadItem(
email: Email,
modifier: Modifier = Modifier
) {
Column(
modifier = modifier
.fillMaxWidth()
.padding(8.dp)
.background(
MaterialTheme.colorScheme.background,
MaterialTheme.shapes.medium
)
.padding(16.dp)
) {
// List item content
}
}
يؤدي تشغيل تطبيقك الآن إلى عرض عنصر قائمة شاشة تفصيلي على شكل medium
.
8. التوكيد
ومن خلال ميزة التوكيد في واجهة المستخدم، يمكنك إبراز بعض المحتوى بدلاً من المحتوى الآخر، مثلاً عندما تريد التمييز بين العنوان والترجمة. التوكيد في M3 يستخدم أشكالاً مختلفة من الألوان ومجموعاتها على الألوان. لديك طريقتان لإضافة التوكيد:
- استخدام السطح وتباين السطح والخلفية إلى جانب الألوان على السطح والمتغيرات على السطح من نظام الألوان M3 الموسَّع
على سبيل المثال، يمكن استخدام السطح مع المتغير السطحي، ويمكن استخدام متغير السطح مع الشكل السطحي لتوفير مستويات مختلفة من التوكيد.
ويمكن أيضًا استخدام خيارات السطح مع ألوان التمييز لتوفير تركيز أقل من الألوان البارزة، ولكن مع إمكانية الوصول إليها واتّباع نسبة التباين.
أدوار ألوان خيارات سطح السطح والخلفية والسطح
- استخدام سُمك خط مختلفة للنص كما رأيت في قسم أسلوب الخط، يمكنك توفير ترجيحات مخصصة لمقياس الكتابة لتوفير توكيد مختلف.
بعد ذلك، يجب تعديل ReplyEmailListItem.kt
لعرض فرق التوكيد باستخدام خيار السطح. حسب الإعدادات التلقائية، سيظهر محتوى البطاقة بلون المحتوى التلقائي استنادًا إلى الخلفية.
سيتم تعديل لون نص الوقت ولون النص الأساسي القابل للإنشاء إلى onSurfaceVariant
. يؤدي ذلك إلى تقليل مستوى التوكيد مقارنةً بـ onContainerColors
، والذي يتم تطبيقه تلقائيًا على نص الموضوع والعنوان القابل للإنشاء.
الوقت والنص الأساسي مع التركيز نفسه على الموضوع والعنوان (على اليسار).
الوقت والجسم مع انخفاض التركيز على الموضوع والعنوان (على اليمين).
ReplyEmailListItem.kt
Text(
text = email.createdAt,
style = MaterialTheme.typography.labelMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
Text(
text = email.body,
maxLines = 2,
style = MaterialTheme.typography.bodyLarge,
color = MaterialTheme.colorScheme.onSurfaceVariant
overflow = TextOverflow.Ellipsis
)
بالنسبة إلى بطاقة البريد الإلكتروني المهمة التي تظهر في الخلفية secondaryContainer
، يكون كل ألوان النص هو onSecondaryContainer
تلقائيًا. بالنسبة إلى الرسائل الإلكترونية الأخرى، تكون الخلفية surfaceVariant,
، وبالتالي يكون اللون التلقائي لكل النص onSurfaceVariant
.
9. تهانينا
تهانينا لقد أكملت هذا الدرس التطبيقي حول الترميز بنجاح. لقد نفذت مظاهر Material باستخدام Compose باستخدام الألوان وأسلوب الخط والأشكال إلى جانب الألوان الديناميكية لموضوع تطبيقك وتوفير تجربة مخصصة.
يتم تطبيق نهاية نتائج البحث باستخدام ألوان ديناميكية ومظهر ألوان.
الخطوات التالية
يمكنك الاطّلاع على الدروس التطبيقية الأخرى حول الترميز في مسار الإنشاء:
محتوى إضافي للقراءة
- دليل إنشاء المواضيع
- تخصيص التصميم المتعدد الأبعاد في ميزة Compose
نماذج التطبيقات
- الرد على نموذج التطبيق مع تضمين مظهر Material 3 الكاملة
- JetChat عرض المظاهر الديناميكية