การกำหนดธีมใน Compose ด้วย Material 3

1. บทนำ

ใน Codelab นี้ คุณจะได้เรียนรู้เกี่ยวกับการกำหนดธีมแอปใน Jetpack Compose โดยใช้ Material Design 3 นอกจากนี้ คุณยังจะได้เรียนรู้เกี่ยวกับองค์ประกอบสำคัญของรูปแบบสี การออกแบบตัวอักษร และรูปร่างของ Material Design 3 ซึ่งจะช่วยให้คุณจัดธีมแอปพลิเคชันในแบบที่เป็นส่วนตัวและเข้าถึงได้

นอกจากนี้ คุณจะได้ดูการรองรับการกำหนดธีมแบบไดนามิกพร้อมกับระดับการเน้นที่แตกต่างกัน

สิ่งที่คุณจะได้เรียนรู้

ใน Codelab นี้ คุณจะได้เรียนรู้สิ่งต่อไปนี้

  • ลักษณะสำคัญของการกำหนดธีม Material 3
  • รูปแบบสี Material 3 และวิธีสร้างธีมสำหรับแอป
  • วิธีรองรับการกำหนดธีมแบบไดนามิกและธีมสว่าง/มืดสำหรับแอป
  • การจัดรูปแบบข้อความและรูปร่างเพื่อปรับเปลี่ยนแอปในแบบของคุณ
  • คอมโพเนนต์ Material 3 และการปรับแต่งเพื่อจัดรูปแบบแอป

สิ่งที่คุณจะสร้าง

ใน Codelab นี้ คุณจะกำหนดธีมให้โปรแกรมรับส่งอีเมลชื่อ Reply คุณเริ่มต้นด้วยแอปพลิเคชันที่ไม่ได้จัดรูปแบบโดยใช้ธีมพื้นฐาน และจะนำสิ่งที่ได้เรียนรู้ไปใช้เพื่อจัดธีมแอปพลิเคชันและรองรับธีมมืด

d15db3dc75a9d00f.png

จุดเริ่มต้นเริ่มต้นของแอปของเราที่มีธีมพื้นฐาน

คุณจะสร้างธีมด้วยชุดรูปแบบสี การพิมพ์ และรูปร่าง จากนั้นนำไปใช้กับรายชื่ออีเมลและหน้ารายละเอียดของแอป นอกจากนี้ คุณยังจะเพิ่มการรองรับธีมแบบไดนามิกลงในแอปด้วย เมื่อสิ้นสุด Codelab คุณจะได้รับการรองรับทั้งธีมสีและธีมแบบไดนามิกสำหรับแอป

1357cdbfaaa67721.png

จุดสิ้นสุดของ Codelab การกำหนดธีมที่มีการกำหนดธีมสีอ่อนและการกำหนดธีมแบบไดนามิกสีอ่อน

1357cdbfaaa67721.png

จุดสิ้นสุดของโค้ดแล็บการกำหนดธีมที่มีการกำหนดธีมสีเข้มและการกำหนดธีมแบบไดนามิกสีเข้ม

สิ่งที่คุณต้องมี

2. การเริ่มตั้งค่า

ในขั้นตอนนี้ คุณจะดาวน์โหลดโค้ดทั้งหมดของแอป Reply ซึ่งคุณจะจัดรูปแบบใน Codelab นี้

รับโค้ด

คุณดูโค้ดสำหรับ Codelab นี้ได้ในที่เก็บ GitHub ของ android-compose-codelabs หากต้องการโคลน ให้เรียกใช้คำสั่งต่อไปนี้

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

หรือจะดาวน์โหลดไฟล์ ZIP 2 ไฟล์ก็ได้

ดูแอปตัวอย่าง

โค้ดที่คุณเพิ่งดาวน์โหลดมีโค้ดสำหรับ Compose Codelab ที่พร้อมใช้งานทั้งหมด หากต้องการทำ Codelab นี้ให้เสร็จสมบูรณ์ ให้เปิดโปรเจ็กต์ ThemingCodelab ใน Android Studio

เราขอแนะนำให้คุณเริ่มต้นด้วยโค้ดในสาขาหลักและทำตาม Codelab ทีละขั้นตอนตามที่คุณสะดวก คุณเรียกใช้เวอร์ชันใดก็ได้ใน Android Studio ได้ทุกเมื่อโดยเปลี่ยนสาขา Git ของโปรเจ็กต์

สำรวจรหัสเริ่มต้น

โค้ดหลักมีแพ็กเกจ UI ซึ่งมีแพ็กเกจและไฟล์หลักต่อไปนี้ที่คุณจะโต้ตอบด้วย

  • MainActivity.kt - กิจกรรมจุดแรกเข้าที่คุณเริ่มแอป Reply
  • com.example.reply.ui.theme - แพ็กเกจนี้มีธีม การออกแบบตัวอักษร และรูปแบบสี คุณจะเพิ่มการจัดธีม Material ในแพ็กเกจนี้
  • com.example.reply.ui.components – มีคอมโพเนนต์ที่กำหนดเองของแอป เช่น รายการในรายการ แถบแอป ฯลฯ คุณจะใช้ธีมกับคอมโพเนนต์เหล่านี้
  • ReplyApp.kt - นี่คือฟังก์ชันที่ประกอบกันได้หลักของเราซึ่งเป็นจุดเริ่มต้นของแผนผัง UI คุณจะใช้การจัดธีมระดับบนสุดในไฟล์นี้

Codelab นี้จะเน้นที่ไฟล์แพ็กเกจ ui

3. การกำหนดธีม Material 3

Jetpack Compose มีการติดตั้งใช้งาน Material Design ซึ่งเป็นระบบการออกแบบที่ครอบคลุมสำหรับการสร้างอินเทอร์เฟซดิจิทัล คอมโพเนนต์ของ Material Design (ปุ่ม การ์ด สวิตช์ ฯลฯ) สร้างขึ้นบนการกำหนดธีม Material ซึ่งเป็นวิธีที่เป็นระบบในการปรับแต่ง Material Design เพื่อให้แสดงถึงแบรนด์ของผลิตภัณฑ์ได้ดียิ่งขึ้น

ธีม Material 3 ประกอบด้วยระบบย่อยต่อไปนี้เพื่อเพิ่มการกำหนดธีมลงในแอป รูปแบบสี การพิมพ์ และรูปร่าง เมื่อปรับแต่งค่าเหล่านี้ การเปลี่ยนแปลงจะแสดงในคอมโพเนนต์ M3 ที่คุณใช้สร้างแอปโดยอัตโนมัติ มาดูแต่ละระบบย่อยและนำไปใช้ในแอปตัวอย่างกัน

ระบบย่อยของดีไซน์ Material: สี แบบตัวพิมพ์ และรูปร่าง

ระบบย่อยของสี การพิมพ์ และรูปร่างของ Material 3

4. รูปแบบสี

รากฐานของรูปแบบสีคือชุดสีหลัก 5 สี ซึ่งแต่ละสีจะเชื่อมโยงกับชุดสี 13 โทนที่คอมโพเนนต์ Material 3 ใช้

สีหลักพื้นฐาน 5 สีสำหรับการสร้างธีม M3

สีหลักพื้นฐาน 5 สีสำหรับการสร้างธีม M3

จากนั้นจะมีการระบุสีเฉพาะจุดแต่ละสี (หลัก รอง และระดับที่ 3) ใน 4 สีที่เข้ากันได้ซึ่งมีโทนสีต่างกันสำหรับการจับคู่ การกำหนดการเน้น และการแสดงภาพ

สีโทน 4 สีของสีเน้นพื้นฐานหลัก รอง และตติยภูมิ

สีโทน 4 สีของสีเน้นพื้นฐานที่เป็นสีหลัก สีรอง และสีตติยภูมิ

ในทำนองเดียวกัน สีกลางจะแบ่งออกเป็น 4 โทนที่เข้ากันได้ซึ่งใช้สำหรับพื้นผิวและพื้นหลัง นอกจากนี้ ยังมีความสำคัญในการเน้นไอคอนข้อความเมื่อวางบนแพลตฟอร์มใดก็ตาม

สีโทน 4 สีของสีกลางพื้นฐาน

สีโทน 4 สีของสีกลางพื้นฐาน

อ่านเพิ่มเติมเกี่ยวกับรูปแบบสีและบทบาทของสี

การสร้างรูปแบบสี

แม้ว่าคุณจะสร้าง ColorScheme ที่กำหนดเองด้วยตนเองได้ แต่การสร้างโดยใช้สีต้นทางจากแบรนด์มักจะง่ายกว่า เครื่องมือ Material Theme Builder ช่วยให้คุณทำสิ่งนี้ได้ และยังส่งออกโค้ดการจัดธีม Compose ได้ด้วย (ไม่บังคับ)

คุณเลือกสีใดก็ได้ตามต้องการ แต่สำหรับกรณีการใช้งานของเรา คุณจะต้องใช้สีหลักเริ่มต้นของ Reply #825500 คลิกสีหลักในส่วนสีหลักทางด้านซ้าย แล้วเพิ่มโค้ดในเครื่องมือเลือกสี

294f73fc9d2a570e.png

การเพิ่มรหัสสีหลักในเครื่องมือสร้างธีม Material

เมื่อเพิ่มสีหลักใน Material Theme Builder แล้ว คุณควรเห็นธีมต่อไปนี้และตัวเลือกในการส่งออกที่มุมขวาบน สำหรับ Codelab นี้ คุณจะส่งออกธีมใน Jetpack Compose

เครื่องมือสร้างธีม Material พร้อมตัวเลือกในการส่งออกที่มุมขวาบน

Material Theme Builder พร้อมตัวเลือกในการส่งออกที่มุมขวาบน

สีหลัก #825500 จะสร้างธีมต่อไปนี้ที่คุณจะเพิ่มลงในแอป Material 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 คือ Composable ของ MaterialTheme

คุณจะรวม MaterialTheme() ที่ประกอบกันได้ไว้ในฟังก์ชัน AppTheme() ซึ่งใช้พารามิเตอร์ 2 รายการ ดังนี้

  • 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 ให้รวม Composable หลัก ReplyApp ไว้กับฟังก์ชันการจัดธีมหลัก AppTheme()

MainActivity.kt

setContent {
   val uiState by viewModel.uiState.collectAsStateWithLifecycle()

   AppTheme {
       ReplyApp(/*..*/)
   }
}

นอกจากนี้ คุณยังต้องอัปเดตฟังก์ชันแสดงตัวอย่างเพื่อดูธีมที่ใช้กับตัวอย่างแอปด้วย ห่อหุ้ม ReplyApp Composable ภายใน ReplyAppPreview() ด้วย AppTheme เพื่อใช้การกำหนดธีมกับตัวอย่าง

คุณมีทั้งธีมระบบสว่างและมืดที่กำหนดไว้ในพารามิเตอร์ตัวอย่าง ดังนั้นคุณจะเห็นทั้ง 2 ตัวอย่าง

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.png be7a661b4553167b.png

แอปที่มีธีมพื้นฐาน (ซ้าย)

แอปที่มีธีมสีที่นำเข้า (ขวา)

674cec6cc12db6a0.png

ตัวอย่างแอปธีมสว่างและธีมมืดที่มีธีมสีที่นำเข้า

Material 3 รองรับทั้งรูปแบบสีสว่างและสีเข้ม คุณได้ห่อหุ้มแอปด้วยธีมที่นำเข้าเท่านั้น คอมโพเนนต์ Material 3 ใช้บทบาทสีเริ่มต้น

มาดูบทบาทของสีและการใช้งานก่อนที่จะเริ่มเพิ่มลงในแอปกัน

บทบาทของสีและการช่วยเหลือพิเศษ

บทบาทของสีแต่ละสีสามารถใช้ได้ในหลายที่ ขึ้นอยู่กับสถานะ ความโดดเด่น และการเน้นของคอมโพเนนต์

1f184a05ea57aa84.png

บทบาทของสีหลัก สีรอง และสีระดับที่ 3

สีหลักคือสีพื้นฐานที่ใช้กับคอมโพเนนต์หลัก เช่น ปุ่มที่โดดเด่นและสถานะที่ใช้งานอยู่

ระบบจะใช้สีคีย์รองกับคอมโพเนนต์ที่โดดเด่นน้อยกว่าใน UI เช่น ชิปตัวกรอง

สีคีย์ตติยภูมิใช้เพื่อเน้นสีที่ตัดกัน และสีกลางใช้สำหรับพื้นหลังและพื้นผิวในแอป

ระบบสีของ Material มีค่าเฉดสีและการวัดมาตรฐานที่ใช้เพื่อให้เป็นไปตามอัตราส่วนคอนทราสต์ที่เข้าถึงได้ ใช้สี "on-primary" บนสี "primary", "on-primary-container" บน "primary-container" และใช้สีเดียวกันกับสีเน้นและสีกลางอื่นๆ เพื่อให้ผู้ใช้เข้าถึงคอนทราสต์ได้

ดูข้อมูลเพิ่มเติมได้ที่บทบาทของสีและการช่วยเหลือพิเศษ

การยกระดับโทนสีและเงา

Material 3 แสดงระดับความสูงโดยใช้การวางซ้อนสีโทนเป็นหลัก นี่เป็นวิธีใหม่ในการแยกความแตกต่างของคอนเทนเนอร์และแพลตฟอร์มจากกัน โดยการเพิ่มระดับโทนสีจะใช้โทนสีที่โดดเด่นมากขึ้น นอกเหนือจากเงา

การยกระดับสีด้วยการยกระดับเงา การยกระดับโทนสีที่ระดับ 2 ซึ่งใช้สีจากช่องสีหลัก

การซ้อนทับระดับความสูงในธีมมืดยังเปลี่ยนเป็นการซ้อนทับสีโทนใน Material Design 3 ด้วย สีซ้อนทับมาจากช่องสีหลัก

M3 Surface ซึ่งเป็นพื้นหลังที่ใช้ได้กับคอมโพเนนต์ M3 ส่วนใหญ่รองรับทั้งการยกระดับโทนสีและการยกระดับเงา

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

การเพิ่มสีลงในแอป

หากเรียกใช้แอป คุณจะเห็นสีที่ส่งออกแสดงในแอปที่คอมโพเนนต์ใช้สีเริ่มต้น ตอนนี้เราทราบถึงบทบาทและการใช้งานสีแล้ว มาจัดธีมแอปด้วยบทบาทสีที่ถูกต้องกัน

be7a661b4553167b.png

แอปที่มีธีมสีและคอมโพเนนต์ที่ใช้บทบาทสีเริ่มต้น

สีพื้นผิว

ในหน้าจอหลัก คุณจะเริ่มต้นด้วยการห่อ Composable ของแอปหลักใน Surface() เพื่อเป็นฐานให้วางเนื้อหาของแอปไว้ด้านบน เปิด MainActivity.kt แล้วห่อ Composable ReplyApp() ด้วย Surface

นอกจากนี้ คุณยังต้องระบุระดับความสูงของสีเป็น 5.dp เพื่อให้พื้นผิวมีสีของช่องหลัก ซึ่งจะช่วยให้เกิดคอนทราสต์กับรายการในลิสต์และแถบค้นหาที่อยู่ด้านบน โดยค่าเริ่มต้น ระดับความสูงของโทนสีและเงาสำหรับพื้นผิวคือ 0.dp

MainActivity.kt

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

หากเรียกใช้แอปพลิเคชันตอนนี้และเห็นทั้งหน้า List และหน้า Detail คุณควรเห็นพื้นผิวสีที่ใช้กับทั้งแอป

be7a661b4553167b.png e70d762495173610.png

พื้นหลังของแอปที่ไม่มีสีพื้นผิวและสีโทน (ซ้าย)

พื้นหลังของแอปที่มีการใช้สีพื้นผิวและสีโทน (ขวา)

สีแถบแอป

แถบค้นหาที่กำหนดเองของเราที่ด้านบนไม่มีพื้นหลังที่ชัดเจนตามคำขอการออกแบบ โดยค่าเริ่มต้น ระบบจะเปลี่ยนกลับไปใช้พื้นผิวฐานเริ่มต้น คุณสามารถใส่พื้นหลังเพื่อให้แยกกันอย่างชัดเจน

5779fc399d8a8187.png

แถบค้นหาที่กำหนดเองไม่มีพื้นหลัง (ซ้าย)

แถบค้นหาที่กำหนดเองพร้อมพื้นหลัง (ขวา)

ตอนนี้คุณจะแก้ไข ui/components/ReplyAppBars.kt ซึ่งมีแถบแอป คุณจะเพิ่ม MaterialTheme.colorScheme.background ไปยัง Row ของ Composable Modifier

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 ขนาดใหญ่ตามธีมที่มีสีระดับที่ 3 (ขวา)

ในหน้าจอหลัก คุณสามารถปรับปรุงลักษณะของปุ่มการทำงานแบบลอย (FAB) เพื่อให้โดดเด่นเป็นปุ่มกระตุ้นให้ดำเนินการได้ หากต้องการใช้ฟีเจอร์นี้ คุณจะต้องใช้สีเฉพาะจุดระดับที่ 3 กับปุ่ม

ในไฟล์ ReplyListContent.kt ให้อัปเดต containerColor สำหรับ FAB เป็นสี tertiaryContainer และสีเนื้อหาเป็น onTertiaryContainer เพื่อรักษาการช่วยเหลือพิเศษและความคมชัดของสี

ReplyListContent.kt

ReplyInboxScreen(/*..*/) {
// Email list content
  LargeFloatingActionButton(
    containerColor = MaterialTheme.colorScheme.tertiaryContainer,
    contentColor = MaterialTheme.colorScheme.onTertiaryContainer
  ){
   /*..*/   
  }
}

เรียกใช้แอปเพื่อดู FAB ที่มีธีม สำหรับ Codelab นี้ คุณจะใช้ 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
   )
){
  /*..*/   
}

5818200be0b01583.png 9367d40023db371d.png

ไฮไลต์รายการโดยใช้สีคอนเทนเนอร์รองบนพื้นผิวโทนสี

สีของรายการรายละเอียด

ตอนนี้คุณได้จัดธีมหน้าจอหลักแล้ว ดูหน้ารายละเอียดโดยคลิกรายการในรายชื่ออีเมล

7a9ea7cf3e91e9c7.png 79b3874aeca4cd1.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 ซึ่งอัลกอริทึมจะดึงสีแบบกำหนดเองจากวอลเปเปอร์ของผู้ใช้เพื่อนำไปใช้กับแอปและ UI ของระบบ

การกำหนดธีมแบบไดนามิกช่วยให้แอปปรับเปลี่ยนในแบบของคุณมากขึ้น นอกจากนี้ ยังมอบประสบการณ์การใช้งานที่สอดคล้องและราบรื่นให้แก่ผู้ใช้ด้วยธีมของระบบ

สีไดนามิกพร้อมใช้งานใน 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
     )
}

fecc63b4c6034236.png

ธีมแบบไดนามิกที่นำมาจากวอลเปเปอร์ Android 13

เมื่อเรียกใช้แอปในตอนนี้ คุณควรเห็นการใช้การกำหนดธีมแบบไดนามิกโดยใช้วอลเปเปอร์เริ่มต้นของ Android 13

นอกจากนี้ คุณอาจต้องการให้แถบสถานะจัดรูปแบบแบบไดนามิกตามรูปแบบสีที่ใช้ในการกำหนดธีมแอปด้วย

1095e2b2c1ffdc14.png

แอปที่ไม่ได้ใช้สีแถบสถานะ (ซ้าย)

แอปที่ใช้สีแถบสถานะแล้ว (ขวา)

หากต้องการอัปเดตสีแถบสถานะตามสีหลักของธีม ให้เพิ่มสีแถบสถานะหลังจากการเลือกรูปแบบสีใน 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
   )
}

เมื่อเรียกใช้แอป คุณควรเห็นแถบสถานะใช้ธีมสีหลัก นอกจากนี้ คุณยังลองใช้การกำหนดธีมแบบไดนามิกทั้งแบบสว่างและมืดได้โดยเปลี่ยนธีมมืดของระบบ

69093b5bce31fd43.png

ธีมสว่าง (ซ้าย) และธีมมืด (ขวา) แบบไดนามิกที่ใช้กับวอลเปเปอร์เริ่มต้นของ Android 13

ที่ผ่านมา คุณได้ใช้สีกับแอปเพื่อปรับปรุงรูปลักษณ์ของแอป อย่างไรก็ตาม คุณจะเห็นว่าข้อความทั้งหมดในแอปมีขนาดเท่ากัน ดังนั้นตอนนี้คุณจึงเพิ่มการจัดรูปแบบข้อความลงในแอปได้แล้ว

6. การพิมพ์

Material Design 3 กำหนดขนาดตัวอักษร เราได้ลดความซับซ้อนของการตั้งชื่อและการจัดกลุ่มเป็นดังนี้ โฆษณา Display, บรรทัดแรก, ชื่อ, ข้อความ และป้ายกำกับ โดยมีขนาดใหญ่ กลาง และเล็กสำหรับแต่ละรายการ

999a161dcd9b0ec4.png

มาตราส่วนประเภทวัสดุ 3

การกำหนดแบบตัวพิมพ์

Compose มีคลาส Typography ของ M3 รวมถึงคลาส TextStyle และ font-related ที่มีอยู่เพื่อสร้างรูปแบบมาตราส่วนประเภท Material 3

ตัวสร้างการพิมพ์มีค่าเริ่มต้นสำหรับแต่ละสไตล์ คุณจึงละเว้นพารามิเตอร์ที่ไม่ต้องการปรับแต่งได้ ดูข้อมูลเพิ่มเติมได้ที่รูปแบบการพิมพ์และค่าเริ่มต้น

คุณจะใช้รูปแบบการพิมพ์ 5 รูปแบบในแอป ได้แก่ 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() Composable ภายใน 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.kt

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

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

ผลิตภัณฑ์ของคุณอาจไม่จำเป็นต้องใช้รูปแบบเริ่มต้นทั้ง 15 รูปแบบจากขนาดตัวอักษรของ Material Design ในโค้ดแล็บนี้ เราจะเลือก 5 ขนาดและละเว้นขนาดอื่นๆ

เนื่องจากคุณไม่ได้ใช้การจัดรูปแบบข้อความกับ Composable 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.png 6c4af2f412c18bfb.png

หน้าจอหลักที่ไม่ได้ใช้การจัดรูปแบบข้อความ (ซ้าย)

หน้าจอหลักที่ใช้การจัดรูปแบบข้อความ (ขวา)

การพิมพ์รายการรายละเอียด

ในทำนองเดียวกัน คุณจะเพิ่มการออกแบบตัวอักษรในหน้าจอรายละเอียดได้โดยการอัปเดตข้อความที่ใช้ร่วมกันได้ทั้งหมดของ 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
)

543ac09e43d8761.png 3412771e95a45f36.png

หน้าจอรายละเอียดที่ไม่ได้ใช้การจัดรูปแบบข้อความ (ซ้าย)

หน้าจอรายละเอียดที่มีการใช้การจัดรูปแบบข้อความ (ขวา)

การปรับแต่งตัวอักษร

ฟีเจอร์ช่วยเขียนช่วยให้คุณปรับแต่งสไตล์ข้อความหรือระบุแบบอักษรที่กำหนดเองได้ง่ายๆ คุณสามารถแก้ไข 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. รูปร่าง

พื้นผิวของ Material จะแสดงในรูปทรงต่างๆ ได้ รูปร่างดึงดูดความสนใจ ระบุคอมโพเนนต์ สื่อสารสถานะ และแสดงแบรนด์

การกำหนดรูปทรง

Compose มีคลาส Shapes พร้อมพารามิเตอร์ที่ขยายเพื่อใช้รูปร่าง M3 ใหม่ สเกลรูปร่าง M3 คล้ายกับสเกลประเภท ซึ่งช่วยให้มีรูปร่างที่หลากหลายใน UI

รูปร่างมีหลายขนาดในมาตราส่วนรูปร่าง ดังนี้

  • เล็กพิเศษ
  • เล็ก
  • ปานกลาง
  • ใหญ่
  • ใหญ่พิเศษ

โดยค่าเริ่มต้น รูปร่างแต่ละรูปร่างจะมีค่าเริ่มต้นที่ลบล้างได้ สำหรับแอป คุณจะใช้รูปร่างขนาดกลางเพื่อแก้ไขรายการ แต่ก็ประกาศรูปร่างอื่นๆ ได้เช่นกัน สร้างไฟล์ใหม่ชื่อ 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 แล้ว ให้ส่งไปยัง MaterialTheme ของ M3 เหมือนกับที่ทำกับสีและตัวอักษร

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 3 ทั้งหมดการแมปคอมโพเนนต์ Material โดยใช้รูปร่างประเภทต่างๆ

คุณดูการแมปรูปร่างสำหรับคอมโพเนนต์ทั้งหมดได้ในเอกสารประกอบเกี่ยวกับรูปร่าง

นอกจากนี้ยังมีรูปร่างอื่นๆ อีก 2 แบบที่ใช้ได้ ได้แก่ 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.png 80ee881c41a98c2a.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. การเน้น

การเน้นใน UI ช่วยให้คุณไฮไลต์เนื้อหาบางอย่างเหนือเนื้อหาอื่นๆ ได้ เช่น เมื่อต้องการแยกความแตกต่างของชื่อจากคำบรรยาย การเน้นใน M3 ใช้สีที่หลากหลายและชุดค่าผสมสี คุณเน้นข้อความได้ 2 วิธี ดังนี้

  1. การใช้สีพื้นผิว สีพื้นผิวที่แตกต่างกัน และสีพื้นหลังควบคู่ไปกับสีบนพื้นผิวและสีบนพื้นผิวที่แตกต่างกันจากระบบสี M3 ที่ขยาย

เช่น คุณสามารถใช้ "พื้นผิว" กับ "ตัวแปรบนพื้นผิว" และใช้ "ตัวแปรพื้นผิว" กับ "บนพื้นผิว" เพื่อให้ระดับการเน้นที่แตกต่างกัน

นอกจากนี้ คุณยังใช้สีพื้นผิวที่แตกต่างกันกับสีเฉพาะจุดเพื่อให้เน้นน้อยกว่าสี On-Color ได้ แต่ยังคงเข้าถึงได้และเป็นไปตามอัตราส่วนคอนทราสต์

บทบาทของสีพื้นผิว พื้นหลัง และสีพื้นผิวที่แตกต่างกัน

บทบาทของสีพื้นผิว พื้นหลัง และสีพื้นผิวตัวแปร

  1. การใช้ความหนาของแบบอักษรที่แตกต่างกันสำหรับข้อความ ดังที่เห็นในส่วนการจัดตัวอักษร คุณสามารถระบุน้ำหนักที่กำหนดเองให้กับขนาดตัวอักษรเพื่อเน้นข้อความต่างๆ ได้

จากนั้นอัปเดต ReplyEmailListItem.kt เพื่อให้ความแตกต่างของระดับการเน้นโดยใช้รูปแบบพื้นผิว โดยค่าเริ่มต้น เนื้อหาของการ์ดจะใช้สีเนื้อหาเริ่มต้นตามพื้นหลัง

คุณจะอัปเดตสีของ Composable ของข้อความเวลาและข้อความเนื้อหาเป็น onSurfaceVariant ซึ่งจะลดความสำคัญของข้อความเมื่อเทียบกับ onContainerColors ซึ่งจะใช้กับข้อความเรื่องและข้อความชื่อที่คอมโพสได้โดยค่าเริ่มต้น

2c9b7f2bd016edb8.png 6850ff391f21e4ba.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. ขอแสดงความยินดี

ยินดีด้วย คุณทำ Codelab นี้เสร็จเรียบร้อยแล้ว คุณได้ใช้การจัดธีม Material กับ Compose โดยใช้สี การพิมพ์ และรูปร่างต่างๆ พร้อมกับสีแบบไดนามิกเพื่อจัดธีมแอปพลิเคชันและมอบประสบการณ์การใช้งานที่ปรับเปลี่ยนในแบบของคุณ

2d8fcabf15ac5202.png 5a4d31db0185dca6.png ce009e4ce560834d.png

สิ้นสุดผลลัพธ์การจัดธีมด้วยสีแบบไดนามิกและธีมสีที่ใช้

ขั้นตอนถัดไป

ดู Codelab อื่นๆ ของเราในเส้นทาง Compose

อ่านเพิ่มเติม

แอปตัวอย่าง

  • แอป Reply sample ที่มีธีม Material 3 แบบเต็ม
  • JetChat แสดงการกำหนดธีมแบบไดนามิก

เอกสารอ้างอิง