طرح زمینه در Compose with Material 3

1. معرفی

در این کد لبه، با قالب بندی برنامه های خود در Jetpack Compose با استفاده از طراحی متریال 3 آشنا می شوید. همچنین در مورد بلوک های ساختمانی کلیدی Material Design 3 طرح های رنگی، تایپوگرافی و اشکال، که به شما کمک می کند برنامه خود را به صورت شخصی سازی شده و قالب بندی قالب بندی کنید، خواهید آموخت. راه های قابل دسترس

علاوه بر این، پشتیبانی از تم پویا را به همراه سطوح تاکید مختلف بررسی خواهید کرد.

آنچه خواهید آموخت

در این کد لبه یاد خواهید گرفت:

  • جنبه های کلیدی موضوع بندی Material 3
  • طرح های رنگی متریال 3 و نحوه ایجاد تم برای برنامه شما
  • چگونه از طرح زمینه پویا و روشن/تاریک برای برنامه خود پشتیبانی کنید
  • تایپوگرافی و اشکال برای شخصی سازی برنامه شما
  • مولفه های متریال 3 و سفارشی سازی برای استایل برنامه شما

آنچه خواهید ساخت

در این لبه کد، یک برنامه کلاینت ایمیل به نام Reply را قالب بندی می کنید. شما با یک برنامه بدون استایل شروع می‌کنید، با استفاده از طرح زمینه پایه، و آنچه را که یاد می‌گیرید روی تم برنامه اعمال می‌کنید و از تم‌های تیره پشتیبانی می‌کنید.

d15db3dc75a9d00f.png

نقطه شروع پیش‌فرض برنامه ما با موضوع پایه.

تم خود را با طرح رنگ، تایپوگرافی و اشکال ایجاد می‌کنید و سپس آن را در فهرست ایمیل و صفحه جزئیات برنامه خود اعمال می‌کنید. همچنین پشتیبانی از تم پویا را به برنامه اضافه خواهید کرد. در پایان نرم افزار Codelab، از تم های رنگی و پویا برای برنامه خود پشتیبانی خواهید کرد.

1357cdbfaaa67721.png

نقطه پایانی کد لبه قالب با طرح زمینه رنگی روشن و طرح زمینه پویا روشن.

1357cdbfaaa67721.png

نقطه پایانی از لبه کدهای قالب با طرح زمینه رنگ تیره و طرح زمینه پویا تیره.

آنچه شما نیاز خواهید داشت

2. راه اندازی

در این مرحله، کد کامل اپلیکیشن Reply را که در این کد لبه استایل می دهید، دانلود می کنید.

کد را دریافت کنید

کد این codelab را می توان در مخزن android-compose-codelabs GitHub یافت. برای شبیه سازی آن، اجرا کنید:

$ git clone https://github.com/googlecodelabs/android-compose-codelabs

همچنین می توانید دو فایل فشرده را دانلود کنید:

برنامه نمونه را بررسی کنید

کدی که به تازگی دانلود کردید حاوی کدی برای همه کدهای Compose موجود است. برای تکمیل این کد لبه، پروژه ThemingCodelab را در داخل اندروید استودیو باز کنید.

توصیه می کنیم از کدهای موجود در شعبه اصلی شروع کنید و گام به گام کد لبه را با سرعت خود دنبال کنید. در هر زمان می توانید با تغییر شاخه git پروژه، هر یک از نسخه ها را در اندروید استودیو اجرا کنید.

کاوش کد شروع

کد اصلی حاوی یک بسته رابط کاربری است که دارای بسته‌ها و فایل‌های اصلی زیر است که با آنها تعامل خواهید داشت:

  • MainActivity.kt – فعالیت نقطه ورودی که در آن برنامه Reply را شروع می کنید.
  • com.example.reply.ui.theme – این بسته شامل تم ها، تایپوگرافی و طرح های رنگی است. شما تم Material را در این بسته اضافه خواهید کرد.
  • com.example.reply.ui.components – شامل اجزای سفارشی برنامه مانند موارد فهرست، نوارهای برنامه و غیره است. شما تم ها را برای این مؤلفه ها اعمال خواهید کرد.
  • ReplyApp.kt - این تابع Composable اصلی ما است که درخت UI از آنجا شروع می شود. شما در این فایل قالب سطح بالایی را اعمال خواهید کرد.

این کد لبه روی فایل های بسته رابط ui متمرکز خواهد شد.

3. موضوع بندی مواد 3

Jetpack Compose پیاده سازی Material Design را ارائه می دهد - یک سیستم طراحی جامع برای ایجاد رابط های دیجیتال. اجزای طراحی متریال (دکمه‌ها، کارت‌ها، سوئیچ‌ها و غیره) بر روی Material Theming ساخته شده‌اند، که روشی سیستماتیک برای سفارشی‌سازی متریال دیزاین است تا برند محصول شما را بهتر منعکس کند.

موضوع Material 3 شامل زیرسیستم های زیر برای افزودن طرح زمینه به برنامه شما است: طرح رنگ ، تایپوگرافی و اشکال . وقتی این مقادیر را سفارشی می کنید، تغییرات شما به طور خودکار در مؤلفه های M3 که برای ساختن برنامه خود استفاده می کنید منعکس می شود. بیایید به هر زیرسیستم شیرجه بزنیم و آن را در برنامه نمونه پیاده سازی کنیم.

سیستم های فرعی طراحی مواد: رنگ، تایپوگرافی و اشکال.

مواد 3 زیر سیستم رنگ ها، تایپوگرافی و اشکال.

4. طرح های رنگی

اساس یک طرح رنگی مجموعه ای از پنج رنگ کلیدی است که هر کدام به پالت تونالیستی از 13 تن مربوط می شود که توسط مؤلفه های Material 3 استفاده می شود.

پنج رنگ کلیدی پایه برای ایجاد یک تم M3.

پنج رنگ کلیدی پایه برای ایجاد یک تم M3.

سپس هر رنگ تاکیدی (اولیه، ثانویه و سوم) در چهار رنگ سازگار با تن های مختلف برای جفت شدن، تاکید بر تعریف و بیان بصری ارائه می شود.

چهار رنگ تونال از رنگ های پایه اصلی، ثانویه و درجه سوم.

چهار رنگ تونال از رنگ های پایه اصلی، ثانویه و درجه سوم.

به طور مشابه، رنگ های خنثی نیز به چهار تن سازگار برای سطوح و پس زمینه تقسیم می شوند. این موارد همچنین برای تأکید بر نمادهای متنی هنگام قرارگیری روی هر سطحی مهم هستند.

چهار رنگ تونال رنگ های خنثی پایه.

چهار رنگ تونال رنگ های خنثی پایه.

درباره طرح رنگ و نقش های رنگی بیشتر بخوانید.

ایجاد طرح های رنگی

در حالی که می‌توانید یک ColorScheme سفارشی را به‌صورت دستی ایجاد کنید، اغلب ساده‌تر است که با استفاده از رنگ‌های مبدأ برند خود، آن را ایجاد کنید. ابزار Material Theme Builder به شما این امکان را می دهد که این کار را انجام دهید و به صورت اختیاری کد موضوعی Compose را صادر کنید.

شما می توانید هر رنگی را که دوست دارید انتخاب کنید، اما برای مورد استفاده ما از رنگ اصلی Reply #825500 استفاده می کنید. روی رنگ اصلی در قسمت سمت چپ Core Colors کلیک کنید و کد را در انتخابگر رنگ اضافه کنید.

294f73fc9d2a570e.png

افزودن کد رنگ اصلی در Material Theme Builder.

هنگامی که رنگ اصلی را در Material Theme Builder اضافه کردید، باید تم زیر و گزینه صادرات را در گوشه بالا سمت راست مشاهده کنید. برای این کد لبه، موضوع را در Jetpack Compose صادر می‌کنید.

Material Theme Builder با گزینه ای برای صادرات در گوشه بالا سمت راست.

Material Theme Builder با گزینه صادرات در گوشه بالا سمت راست.

رنگ اصلی #825500 تم زیر را ایجاد می کند که به برنامه اضافه خواهید کرد. متریال 3 طیف گسترده ای از نقش های رنگی را برای بیان انعطاف پذیری حالت، برجستگی و تاکید یک جزء فراهم می کند.

طرح رنگ روشن و تیره از رنگ اصلی صادر شده است.

طرح رنگ روشن و تیره از رنگ اصلی صادر شده است.

فایل ایجاد شده The Color.kt حاوی رنگ های تم شما با تمام نقش های تعریف شده برای رنگ های تم روشن و تیره است.

رنگ.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 Composable است.

شما MaterialTheme() Composable را در تابع 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
           )
       )
   }
}

اگر اکنون برنامه را اجرا می‌کنید، باید پیش‌نمایش برنامه‌ها را با رنگ‌های تم وارد شده به جای طرح زمینه پایه ببینید.

fddf7b9cc99b1fe3.pngbe7a661b4553167b.png

برنامه با موضوع پایه (سمت چپ).

برنامه با تم رنگی وارد شده (راست).

674cec6cc12db6a0.png

پیش نمایش برنامه های روشن و تاریک با تم های رنگی وارداتی.

متریال 3 از طرح های رنگ روشن و تیره پشتیبانی می کند. شما فقط برنامه را با موضوع وارد شده بسته بندی کرده اید. مؤلفه های ماده 3 از نقش های رنگی پیش فرض استفاده می کنند.

بیایید قبل از شروع اضافه کردن آن به برنامه، در مورد نقش های رنگ و استفاده از آن بیاموزیم.

نقش های رنگی و دسترسی

هر نقش رنگی را می توان در مکان های مختلفی بسته به حالت، برجستگی و تاکید جزء مورد استفاده قرار داد.

1f184a05ea57aa84.png

نقش های رنگی رنگ های اولیه، ثانویه و سوم.

رنگ اصلی رنگ پایه است که برای اجزای اصلی مانند دکمه های برجسته و حالت های فعال استفاده می شود.

رنگ کلید ثانویه برای اجزای کمتر برجسته در رابط کاربری مانند تراشه های فیلتر استفاده می شود.

رنگ کلید سوم برای ارائه لهجه های متضاد و رنگ های خنثی برای پس زمینه و سطوح در برنامه استفاده می شود.

سیستم رنگی متریال مقادیر و اندازه‌گیری‌های استاندارد تن را ارائه می‌کند که می‌تواند برای برآوردن نسبت‌های کنتراست قابل دسترس استفاده شود. از روی اصلی در بالای ظرف اصلی، از روی ظرف اصلی در بالای ظرف اصلی، و همینطور برای سایر رنگ‌های تاکیدی و خنثی استفاده کنید تا کنتراست قابل دسترسی را برای کاربر فراهم کنید.

برای اطلاعات بیشتر، نقش‌های رنگی و قابلیت دسترسی را ببینید.

ارتفاعات تونال و سایه

ماده 3 ارتفاع را عمدتاً با استفاده از پوشش های رنگی تونال نشان می دهد. این یک روش جدید برای متمایز کردن ظروف و سطوح از یکدیگر است - علاوه بر سایه ها، افزایش ارتفاع از لحن برجسته تری استفاده می کند.

ارتفاع تونال با ارتفاع سایه ارتفاع تونال در سطح 2 که رنگ را از شکاف رنگ اصلی می گیرد.

پوشش‌های ارتفاعی در تم‌های تیره نیز به پوشش‌های رنگی تونال در طراحی متریال 3 تغییر کرده‌اند. رنگ روکش از شکاف رنگ اصلی می‌آید.

M3 Surface - پشتیبان قابل ترکیب در پشت اکثر اجزای M3 - شامل پشتیبانی از ارتفاع و ارتفاع سایه است:

Surface(
   modifier = modifier,
   tonalElevation = {..}
   shadowElevation = {..}
) {
   Column(content = content)
}

اضافه کردن رنگ به برنامه

اگر برنامه را اجرا کنید، می‌توانید رنگ‌های صادر شده را در برنامه مشاهده کنید که در آن اجزا رنگ‌های پیش‌فرض را دریافت می‌کنند. اکنون که از نقش‌های رنگی و کاربرد آن آگاه شدیم، اجازه دهید برنامه را با نقش‌های رنگی مناسب تم‌بندی کنیم.

be7a661b4553167b.png

برنامه با تم رنگی و اجزایی که نقش های رنگی پیش فرض را دارند.

رنگ های سطحی

در صفحه اصلی، با پیچاندن برنامه اصلی قابل ساخت در یک Surface() شروع می‌کنید تا مبنایی را برای قرار دادن محتوای برنامه در بالای آن فراهم کنید. MainActivity.kt را باز کنید و ReplyApp() را با Surface بپیچید.

شما همچنین یک ارتفاع تونال 5.dp برای دادن رنگ تونال شیار اصلی به سطح ارائه خواهید کرد که به ایجاد کنتراست در برابر آیتم لیست و نوار جستجو در بالای آن کمک می کند. به طور پیش فرض، ارتفاع تونال و سایه برای سطح 0.dp است.

MainActivity.kt

AppTheme {
   Surface(tonalElevation = 5.dp) {
       ReplyApp(
           replyHomeUIState = uiState,
          // other parameters
         )
   }
}

اگر اکنون برنامه خود را اجرا می کنید و هر دو صفحه فهرست و جزئیات را می بینید، باید سطح تونال اعمال شده روی کل برنامه را ببینید.

be7a661b4553167b.pnge70d762495173610.png

پس زمینه برنامه بدون سطح و رنگ تونال (سمت چپ).

پس زمینه برنامه با سطح و رنگ تونال اعمال شده (راست).

رنگ نوار برنامه

نوار جستجوی سفارشی ما در بالای صفحه پس‌زمینه واضحی به درخواست طراحی ندارد. به طور پیش فرض، به سطح پایه پیش فرض برمی گردد. شما می توانید پس زمینه ای برای تفکیک واضح ارائه دهید.

5779fc399d8a8187.png

نوار جستجوی سفارشی بدون پس‌زمینه (سمت چپ).

نوار جستجوی سفارشی با پس‌زمینه (راست).

اکنون ui/components/ReplyAppBars.kt را که حاوی نوار برنامه است، ویرایش خواهید کرد. شما MaterialTheme.colorScheme.background را به Modifier Row Composable اضافه خواهید کرد.

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
   }
}

اکنون باید یک جدایی واضح بین سطح تونال و نوار برنامه با رنگ پس‌زمینه مشاهده کنید.

b1b374b801dadc06.png

نوار جستجو با رنگ پس‌زمینه در بالای سطح تونال.

رنگ های دکمه اکشن شناور

70ceac87233fe466.png

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 را ارائه می دهد.

می‌توانید با ارائه رنگ‌های ثانویه، برخی از موارد مهم را برجسته کنید. با به‌روزرسانی رنگ محفظه کارت با استفاده از CardDefaults.cardColors() برای ایمیل‌های مهم، ui/components/ReplyEmailListItem.kt را تغییر خواهید داد:

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
   )
){
  /*..*/   
}

5818200be0b01583.png9367d40023db371d.png

مورد فهرست را با استفاده از رنگ ظرف ثانویه روی سطح تونال برجسته کنید.

رنگ مورد فهرست جزئیات

اکنون، صفحه اصلی خود را قالب بندی کرده اید. با کلیک بر روی هر یک از موارد لیست ایمیل، به صفحه جزئیات نگاهی بیندازید.

7a9ea7cf3e91e9c7.png79b3874aeca4cd1.png

صفحه جزئیات پیش‌فرض بدون آیتم فهرست مضمون (سمت چپ).

مورد فهرست جزئیات با طرح زمینه پس‌زمینه اعمال شده (راست).

مورد فهرست شما هیچ رنگی روی آن اعمال نمی‌شود، بنابراین به رنگ پیش‌فرض سطح تونال برمی‌گردد. شما رنگ پس‌زمینه را به آیتم فهرست اعمال می‌کنید تا جداسازی ایجاد کنید و برای ایجاد فاصله در اطراف پس‌زمینه ما، بالشتک اضافه کنید.

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. اضافه کردن رنگ های پویا در برنامه

رنگ پویا بخش کلیدی Material 3 است که در آن یک الگوریتم رنگ‌های سفارشی را از تصویر زمینه کاربر استخراج می‌کند تا روی برنامه‌ها و رابط کاربری سیستم اعمال شود.

طرح زمینه پویا برنامه های شما را شخصی تر می کند. همچنین تجربه ای منسجم و یکپارچه با موضوع سیستم را در اختیار کاربران قرار می دهد.

رنگ پویا در اندروید 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
     )
}

fecc63b4c6034236.png

تم پویا برگرفته از والپیپر اندروید 13.

هنگامی که اکنون برنامه را اجرا می کنید، باید با استفاده از تصویر زمینه پیش فرض اندروید 13، تم پویا را مشاهده کنید.

همچنین ممکن است بخواهید نوار وضعیت بسته به طرح رنگی که برای طرح زمینه برنامه شما استفاده می شود، به صورت پویا استایل کند.

1095e2b2c1ffdc14.png

برنامه بدون رنگ نوار وضعیت اعمال شده (سمت چپ).

برنامه با رنگ نوار وضعیت اعمال شده (راست).

برای به روز رسانی رنگ نوار وضعیت بسته به رنگ اصلی طرح زمینه، رنگ نوار وضعیت را بعد از انتخاب طرح رنگ در AppTheme composable اضافه کنید:

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
   )
}

وقتی برنامه را اجرا می کنید، باید نوار وضعیت را ببینید که تم رنگ اصلی شما را می گیرد. همچنین می‌توانید با تغییر طرح زمینه تاریک سیستم، هم تم پویا روشن و هم تاریک را امتحان کنید.

69093b5bce31fd43.png

طرح زمینه روشن پویا (چپ) و تیره (راست) با کاغذدیواری پیش‌فرض Android 13 اعمال می‌شود.

تاکنون، رنگ‌هایی را روی برنامه خود اعمال کرده‌اید که ظاهر برنامه را بهبود بخشیده است. با این حال، می‌توانید ببینید که تمام متن‌های موجود در برنامه به یک اندازه هستند، بنابراین اکنون می‌توانید تایپوگرافی را به برنامه اضافه کنید.

6. تایپوگرافی

Material Design 3 یک مقیاس نوع را تعریف می کند. نامگذاری و گروه بندی به این صورت ساده شده است: نمایش، عنوان، عنوان، بدنه، و برچسب، با اندازه های بزرگ، متوسط ​​و کوچک برای هر کدام.

999a161dcd9b0ec4.png

ترازو نوع ماده 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 t استفاده کنید.

Text(
   text = "Hello M3 theming",
   style = MaterialTheme.typography.titleLarge
)

Text(
   text = "you are learning typography",
   style = MaterialTheme.typography.bodyMedium
)

محصول شما احتمالاً به تمام 15 سبک پیش‌فرض از مقیاس نوع طراحی مواد نیاز ندارد. در این کد، پنج اندازه انتخاب شده در حالی که بقیه حذف شده اند.

از آنجایی که شما تایپوگرافی را برای ترکیب‌بندی‌های 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
)

90645c0765167bb7.png6c4af2f412c18bfb.png

صفحه اصلی بدون تایپوگرافی اعمال شده (سمت چپ).

صفحه اصلی با تایپوگرافی اعمال شده (راست).

تایپوگرافی لیست جزئیات

به طور مشابه، تایپوگرافی را در صفحه جزئیات با به روز رسانی تمام متن های قابل ترکیب ReplyEmailThreadItem در u i/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
)

543ac09e43d8761.png3412771e95a45f36.png

صفحه جزئیات بدون اعمال تایپوگرافی (سمت چپ).

صفحه نمایش جزئیات با تایپوگرافی اعمال شده (راست).

سفارشی کردن تایپوگرافی

با Compose، سفارشی کردن سبک متن یا ارائه فونت سفارشی بسیار آسان است. می توانید 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
),
...

f8d2212819eb0b61.png

استفاده از تایپوگرافی سفارشی در متن موضوع.

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
   )
}

کار با اشکال

درست مانند رنگ و تایپوگرافی، می‌توانید با استفاده از MaterialTheme.shape شکل‌ها را به اجزای Material اعمال کنید، که به شما نمونه Shape برای دسترسی به اشکال Material می‌دهد.

بسیاری از مؤلفه‌های Material قبلاً دارای اشکال پیش‌فرض هستند، اما شما می‌توانید اشکال خود را از طریق شکاف‌های موجود به مؤلفه‌ها ارائه و اعمال کنید.

Card(shape = MaterialTheme.shapes.medium) { /* card content */ }
FloatingActionButton(shape = MaterialTheme.shapes.large) { /* fab content */}

مقادیر اشکال پیش‌فرض برای همه مؤلفه‌های Material 3. نقشه برداری از اجزای مواد با استفاده از انواع مختلف اشکال.

می توانید نگاشت اشکال برای همه اجزاء را در مستندات Shape مشاهده کنید.

دو شکل دیگر برای استفاده وجود دارد - RectangleShape و CircleShape - که بخشی از Compose هستند. شکل مستطیل شعاع حاشیه ای ندارد و شکل دایره لبه های دایره ای کامل را نشان می دهد.

همچنین می‌توانید با استفاده از Modifiers که شکل‌هایی مانند Modifier.clip ، Modifier.background ، و Modifier.border دارند، شکل را به اجزای خود اعمال کنید.

شکل نوار برنامه

ما می خواهیم نوار برنامه یک پس زمینه گوشه گرد داشته باشد:

f873392abe535494.png

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
   }
}

f873392abe535494.png

شکل آیتم فهرست جزئیات

در صفحه اصلی، از کارتی استفاده می کنید که به طور پیش فرض از Shape.Medium استفاده می کند. با این حال، برای صفحه جزئیات ما، به جای آن از یک ستون با رنگ پس‌زمینه استفاده کردید. برای ظاهر یکنواخت لیست، یک شکل متوسط ​​به آن اعمال کنید.

3412771e95a45f36.png80ee881c41a98c2a.png

ستون مورد فهرست جزئیات بدون شکل در مورد لیست (چپ) و شکل متوسط ​​در لیست (راست).

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 از تنوع رنگ و ترکیبات روی رنگ آن استفاده می کند. شما دو راه برای تاکید دارید:

  1. استفاده از سطح، متغیر سطحی، و پس‌زمینه در کنار رنگ‌های مختلف روی سطح و روی سطح از سیستم رنگی توسعه‌یافته M3.

به عنوان مثال، سطح را می توان با متغیر روی سطح استفاده کرد، و سطح را می توان با روی سطح برای ارائه سطوح مختلف تاکید استفاده کرد.

انواع سطحی همچنین می توانند با رنگ های برجسته استفاده شوند تا تاکید کمتری نسبت به رنگ های برجسته داشته باشند، اما همچنان در دسترس باشند و از نسبت کنتراست پیروی کنند.

نقش های رنگی سطح، پس زمینه و سطح.

نقش‌های رنگی سطح، پس‌زمینه و سطح.

  1. استفاده از وزن فونت های مختلف برای متن همانطور که در بخش تایپوگرافی مشاهده کردید، می توانید وزن های سفارشی را به ترازوی نوع خود برای ارائه تاکیدات مختلف ارائه دهید.

در مرحله بعد، ReplyEmailListItem.kt را به روز کنید تا تفاوت تاکیدی را با استفاده از نوع سطحی ارائه دهید. به‌طور پیش‌فرض، محتوای کارت بسته به پس‌زمینه، رنگ محتوای پیش‌فرض را می‌گیرد.

متن زمان و رنگ متن متن قابل ترکیب را به onSurfaceVariant به‌روزرسانی خواهید کرد. این امر تاکید آن را در مقایسه با onContainerColors کاهش می‌دهد که به‌طور پیش‌فرض بر متن‌های قابل نوشتن موضوع و عنوان اعمال می‌شود.

2c9b7f2bd016edb8.png6850ff391f21e4ba.png

زمان و متن متن با تاکید یکسان در مقایسه با موضوع و عنوان (سمت چپ).

زمان و بدن با تاکید کمتر نسبت به موضوع و عنوان (راست).

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 پیاده‌سازی کرده‌اید تا برنامه‌تان را طرح‌بندی کنید و تجربه‌ای شخصی‌سازی کنید.

2d8fcabf15ac5202.png5a4d31db0185dca6.pngce009e4ce560834d.png

پایان طرح‌بندی با رنگ‌های پویا و تم رنگ اعمال می‌شود.

بعدش چی

سایر کدهای ما را در مسیر Compose بررسی کنید:

بیشتر خواندن

نمونه برنامه ها

  • پاسخ نمونه برنامه با موضوع کامل Material 3
  • JetChat طرح زمینه پویا را نشان می دهد

اسناد مرجع