ย้ายข้อมูลจาก Material 2 ไปยัง Material 3 ใน Compose

Material Design 3 เป็นการพัฒนา Material Design ไปอีกขั้น ซึ่งรวมถึงธีม คอมโพเนนต์ และฟีเจอร์การปรับแต่งในแบบของคุณของ Material You ที่อัปเดตแล้ว เช่น สีแบบไดนามิก ซึ่งเป็นการอัปเดต Material Design 2 และสอดคล้องกับรูปแบบภาพและ UI ของระบบแบบใหม่ใน Android 12 ขึ้นไป

คู่มือนี้มุ่งเน้นที่การย้ายข้อมูลจากไลบรารี Compose Material (androidx.compose.material) ใน Jetpack ไปยังไลบรารี Compose Material 3 (androidx.compose.material3) ใน Jetpack

แนวทาง

โดยทั่วไปแล้ว คุณไม่ควรใช้ทั้ง M2 และ M3 ในแอปเดียวในระยะยาว ทั้งนี้เนื่องจากระบบการออกแบบและไลบรารีที่เกี่ยวข้องของ 2 แพลตฟอร์มนี้แตกต่างกันอย่างมากในด้านการออกแบบ UX/UI และการใช้งาน Compose

แอปของคุณอาจใช้ระบบการออกแบบ เช่น ระบบที่สร้างขึ้นโดยใช้ Figma ในกรณีเช่นนี้ เราขอแนะนําอย่างยิ่งให้คุณหรือทีมออกแบบย้ายข้อมูลจาก M2 ไปยัง M3 ก่อนเริ่มย้ายข้อมูล Compose เราไม่แนะนำให้ย้ายข้อมูลแอปไปยัง M3 หากการออกแบบ UX/UI ของแอปนั้นอิงตาม M2

นอกจากนี้ แนวทางในการย้ายข้อมูลควรแตกต่างกันไปตามขนาด ความซับซ้อน และการออกแบบ UX/UI ของแอป ซึ่งจะช่วยคุณลดผลกระทบต่อโค้ดเบส คุณควรทยอยย้ายข้อมูลทีละระยะ

กรณีที่ควรย้ายข้อมูล

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

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

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

แนวทางแบบเป็นระยะ

ขั้นตอนทั่วไปในการย้ายข้อมูลแบบเป็นระยะมีดังนี้

  1. เพิ่มทรัพยากร Dependency ของ M3 ควบคู่ไปกับทรัพยากร Dependency ของ M2
  2. เพิ่มธีมเวอร์ชัน M3 ของแอปควบคู่ไปกับธีมเวอร์ชัน M2 ของแอป
  3. ย้ายข้อมูลโมดูล หน้าจอ หรือคอมโพสิเบิลแต่ละรายการไปยัง M3 โดยขึ้นอยู่กับขนาดและความซับซ้อนของแอป (ดูรายละเอียดในส่วนด้านล่าง)
  4. เมื่อย้ายข้อมูลเสร็จแล้ว ให้นำธีมเวอร์ชัน M2 ของแอปออก
  5. นำข้อกําหนดของ M2 ออก

ทรัพยากร Dependency

M3 มีแพ็กเกจและเวอร์ชันแยกต่างหากจาก M2 ดังนี้

M2

implementation "androidx.compose.material:material:$m2-version"

M3

implementation "androidx.compose.material3:material3:$m3-version"

ดู M3 เวอร์ชันล่าสุดได้ในหน้ารุ่นของ Compose Material 3

Dependency อื่นๆ ของ Material ที่อยู่นอกไลบรารี M2 และ M3 หลักจะไม่มีการเปลี่ยนแปลง โดยลูกค้าใช้แพ็กเกจและเวอร์ชัน M2 และ M3 ผสมกัน แต่จะไม่ส่งผลต่อการย้ายข้อมูล สามารถใช้กับ M3 ได้โดยไม่ต้องแก้ไข

คลัง แพ็กเกจและเวอร์ชัน
เขียนไอคอน Material androidx.compose.material:material-icons-*:$m2-version
เขียน Material Ripple androidx.compose.material:material-ripple:$m2-version

API ทดลอง

API ของ M3 บางรายการถือว่าอยู่ในขั้นทดลอง ในกรณีเช่นนี้ คุณต้องเลือกใช้ที่ระดับฟังก์ชันหรือไฟล์โดยใช้คำอธิบายประกอบ ExperimentalMaterial3Api ดังนี้

import androidx.compose.material3.ExperimentalMaterial3Api

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AppComposable() {
    // M3 composables
}

ธีม

ทั้ง M2 และ M3 คอมโพสิชันธีมจะมีชื่อว่า MaterialTheme แต่แพ็กเกจและพารามิเตอร์การนําเข้าจะแตกต่างกัน ดังนี้

M2

import androidx.compose.material.MaterialTheme

MaterialTheme(
    colors = AppColors,
    typography = AppTypography,
    shapes = AppShapes
) {
    // M2 content
}

M3

import androidx.compose.material3.MaterialTheme

MaterialTheme(
    colorScheme = AppColorScheme,
    typography = AppTypography,
    shapes = AppShapes
) {
    // M3 content
}

สี

การเปรียบเทียบระบบสี M2 กับ M3
รูปที่ 1 ระบบสี M2 (ซ้าย) เทียบกับระบบสี M3 (ขวา)

ระบบสีใน M3 แตกต่างจาก M2 อย่างมาก พารามิเตอร์สีมีจำนวนมากขึ้น มีชื่อแตกต่างกัน และจับคู่กับคอมโพเนนต์ M3 ต่างกัน ในเครื่องมือเขียน การดำเนินการนี้จะมีผลกับคลาส M2 Colors, คลาส M3 ColorScheme และฟังก์ชันที่เกี่ยวข้อง

M2

import androidx.compose.material.lightColors
import androidx.compose.material.darkColors

val AppLightColors = lightColors(
    // M2 light Color parameters
)
val AppDarkColors = darkColors(
    // M2 dark Color parameters
)
val AppColors = if (darkTheme) {
    AppDarkColors
} else {
    AppLightColors
}

M3

import androidx.compose.material3.lightColorScheme
import androidx.compose.material3.darkColorScheme

val AppLightColorScheme = lightColorScheme(
    // M3 light Color parameters
)
val AppDarkColorScheme = darkColorScheme(
    // M3 dark Color parameters
)
val AppColorScheme = if (darkTheme) {
    AppDarkColorScheme
} else {
    AppLightColorScheme
}

เนื่องจากระบบสี M2 และ M3 มีความแตกต่างกันอย่างมาก จึงไม่มีการแมปที่เหมาะสมสําหรับพารามิเตอร์ Color แต่ให้ใช้เครื่องมือสร้างธีม Material เพื่อสร้างรูปแบบสี M3 แทน ใช้สี M2 เป็นสีหลักในเครื่องมือ ซึ่งเครื่องมือจะขยายเป็นชุดสีที่ใช้กับชุดรูปแบบสี M3 เราขอแนะนำให้ใช้การแมปต่อไปนี้เป็นจุดเริ่มต้น

M2 เครื่องมือสร้างธีม Material
primary เสียงหลัก
primaryVariant Secondary
secondary เสียงลำดับสาม
surface หรือ background เฉยๆ
สี M2 ที่ใช้ในเครื่องมือสร้างธีม Material เพื่อสร้างรูปแบบสี M3
รูปที่ 2 สี M2 ของ Jetchat ที่ใช้ใน Material Theme Builder เพื่อสร้างรูปแบบสี M3

คุณสามารถคัดลอกค่ารหัสสีแบบเลขฐาน 16 สำหรับธีมสว่างและธีมมืดจากเครื่องมือนี้ และนำไปใช้กับอินสแตนซ์ M3 ColorScheme ได้ หรือจะใช้ Material Theme Builder เพื่อส่งออกโค้ด Compose ก็ได้

isLight

คลาส M3 ColorScheme ไม่มีพารามิเตอร์ isLight ซึ่งแตกต่างจากคลาส M2 Colors โดยทั่วไป คุณควรลองสร้างโมเดลของสิ่งที่ต้องใช้ข้อมูลนี้ที่ระดับธีม เช่น

M2

import androidx.compose.material.lightColors
import androidx.compose.material.darkColors
import androidx.compose.material.MaterialTheme

@Composable
private fun AppTheme(
  darkTheme: Boolean = isSystemInDarkTheme(),
  content: @Composable () -> Unit
) {
  val colors = if (darkTheme) darkColors(…) else lightColors(…)
  MaterialTheme(
      colors = colors,
      content = content
  )
}

@Composable
fun AppComposable() {
    AppTheme {
        val cardElevation = if (MaterialTheme.colors.isLight) 0.dp else 4.dp
        …
    }
}

M3

import androidx.compose.material3.lightColorScheme
import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.MaterialTheme

val LocalCardElevation = staticCompositionLocalOf { Dp.Unspecified }
@Composable
private fun AppTheme(
   darkTheme: Boolean = isSystemInDarkTheme(),
    content: @Composable () -> Unit
) {
   val cardElevation = if (darkTheme) 4.dp else 0.dp
    CompositionLocalProvider(LocalCardElevation provides cardElevation) {
        val colorScheme = if (darkTheme) darkColorScheme(…) else lightColorScheme(…)
        MaterialTheme(
            colorScheme = colorScheme,
            content = content
        )
    }
}

@Composable
fun AppComposable() {
    AppTheme {
        val cardElevation = LocalCardElevation.current
        …
    }
}

ดูข้อมูลเพิ่มเติมได้ที่คู่มือระบบการออกแบบที่กำหนดเองในเครื่องมือเขียน

สีแบบเปลี่ยนอัตโนมัติ

ฟีเจอร์ใหม่ใน M3 คือสีแบบไดนามิก M3 ColorScheme สามารถใช้สีวอลเปเปอร์ของอุปกรณ์ใน Android 12 ขึ้นไปแทนการใช้สีที่กำหนดเองได้โดยใช้ฟังก์ชันต่อไปนี้

การพิมพ์

การเปรียบเทียบระบบแบบอักษร M2 กับ M3
รูปที่ 3 ระบบแบบอักษร M3 (ซ้าย) เทียบกับระบบแบบอักษร M2 (ขวา)

ระบบแบบอักษรใน M3 แตกต่างจาก M2 จำนวนพารามิเตอร์การจัดรูปแบบตัวอักษรจะใกล้เคียงกัน แต่มีชื่อต่างกันและแมปกับคอมโพเนนต์ M3 ต่างกัน ในเครื่องมือเขียน การดำเนินการนี้จะมีผลกับคลาส M2 Typography และคลาส M3 Typography

M2

import androidx.compose.material.Typography

val AppTypography = Typography(
    // M2 TextStyle parameters
)

M3

import androidx.compose.material3.Typography

val AppTypography = Typography(
    // M3 TextStyle parameters
)

เราขอแนะนำให้ใช้การแมปพารามิเตอร์ TextStyle ต่อไปนี้เป็นจุดเริ่มต้น

M2 M3
h1 displayLarge
h2 displayMedium
h3 displaySmall
ไม่มี headlineLarge
h4 headlineMedium
h5 headlineSmall
h6 titleLarge
subtitle1 titleMedium
subtitle2 titleSmall
body1 bodyLarge
body2 bodyMedium
caption bodySmall
button labelLarge
ไม่มี labelMedium
overline labelSmall

รูปทรง

การเปรียบเทียบระบบรูปร่าง M2 กับ M3
รูปที่ 4 ระบบรูปร่าง M2 (ซ้าย) เทียบกับระบบรูปร่าง M3 (ขวา)

ระบบรูปร่างใน M3 แตกต่างจาก M2 จำนวนพารามิเตอร์รูปร่างเพิ่มขึ้น มีการตั้งชื่อต่างกัน และจับคู่กับคอมโพเนนต์ M3 ต่างกัน ในเครื่องมือเขียน การตั้งค่านี้จะมีผลกับคลาส M2 Shapes และคลาส M3 Shapes

M2

import androidx.compose.material.Shapes

val AppShapes = Shapes(
    // M2 Shape parameters
)

M3

import androidx.compose.material3.Shapes

val AppShapes = Shapes(
    // M3 Shape parameters
)

เราขอแนะนําให้ใช้การแมปพารามิเตอร์ Shape ต่อไปนี้เป็นจุดเริ่มต้น

M2 M3
ไม่มี extraSmall
small small
medium medium
large large
ไม่มี extraLarge

คอมโพเนนต์และเลย์เอาต์

คอมโพเนนต์และเลย์เอาต์ส่วนใหญ่จาก M2 พร้อมใช้งานใน M3 อย่างไรก็ตาม ยังมีบางรายการที่หายไป รวมถึงรายการใหม่ที่ไม่มีใน M2 นอกจากนี้ คอมโพเนนต์ M3 บางรายการยังมีรูปแบบมากกว่าคอมโพเนนต์ที่เทียบเท่าใน M2 โดยทั่วไปแล้ว อินเทอร์เฟซ API ของ M3 จะพยายามคล้ายกับอินเทอร์เฟซที่เทียบเท่าที่สุดใน M2 มากที่สุด

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

แม้ว่าบางคอมโพเนนต์จะต้องพิจารณาเป็นพิเศษ แต่เราขอแนะนําให้ใช้การแมปฟังก์ชันต่อไปนี้เป็นจุดเริ่มต้น

API ที่ขาดหายไป

M2 M3
androidx.compose.material.swipeable ยังไม่พร้อมใช้งาน

API ที่แทนที่

M2 M3
androidx.compose.material.BackdropScaffold ไม่มีรายการที่เทียบเท่าใน M3 ให้ย้ายข้อมูลไปยัง Scaffold หรือ BottomSheetScaffold แทน
androidx.compose.material.BottomDrawer ไม่มีรายการที่เทียบเท่าใน M3 ให้ย้ายข้อมูลไปยัง ModalBottomSheet แทน

API ที่เปลี่ยนชื่อ

M2 M3
androidx.compose.material.BottomNavigation androidx.compose.material3.NavigationBar
androidx.compose.material.BottomNavigationItem androidx.compose.material3.NavigationBarItem
androidx.compose.material.Chip androidx.compose.material3.AssistChip หรือ androidx.compose.material3.SuggestionChip
androidx.compose.material.ModalBottomSheetLayout androidx.compose.material3.ModalBottomSheet
androidx.compose.material.ModalDrawer androidx.compose.material3.ModalNavigationDrawer

API อื่นๆ ทั้งหมด

M2 M3
androidx.compose.material.AlertDialog androidx.compose.material3.AlertDialog
androidx.compose.material.Badge androidx.compose.material3.Badge
androidx.compose.material.BadgedBox androidx.compose.material3.BadgedBox
androidx.compose.material.BottomAppBar androidx.compose.material3.BottomAppBar
androidx.compose.material.BottomSheetScaffold androidx.compose.material3.BottomSheetScaffold
androidx.compose.material.Button androidx.compose.material3.Button
androidx.compose.material.Card androidx.compose.material3.Card
androidx.compose.material.Checkbox androidx.compose.material3.Checkbox
androidx.compose.material.CircularProgressIndicator androidx.compose.material3.CircularProgressIndicator
androidx.compose.material.Divider androidx.compose.material3.Divider
androidx.compose.material.DropdownMenu androidx.compose.material3.DropdownMenu
androidx.compose.material.DropdownMenuItem androidx.compose.material3.DropdownMenuItem
androidx.compose.material.ExposedDropdownMenuBox androidx.compose.material3.ExposedDropdownMenuBox
androidx.compose.material.ExtendedFloatingActionButton androidx.compose.material3.ExtendedFloatingActionButton
androidx.compose.material.FilterChip androidx.compose.material3.FilterChip
androidx.compose.material.FloatingActionButton androidx.compose.material3.FloatingActionButton
androidx.compose.material.Icon androidx.compose.material3.Icon
androidx.compose.material.IconButton androidx.compose.material3.IconButton
androidx.compose.material.IconToggleButton androidx.compose.material3.IconToggleButton
androidx.compose.material.LeadingIconTab androidx.compose.material3.LeadingIconTab
androidx.compose.material.LinearProgressIndicator androidx.compose.material3.LinearProgressIndicator
androidx.compose.material.ListItem androidx.compose.material3.ListItem
androidx.compose.material.NavigationRail androidx.compose.material3.NavigationRail
androidx.compose.material.NavigationRailItem androidx.compose.material3.NavigationRailItem
androidx.compose.material.OutlinedButton androidx.compose.material3.OutlinedButton
androidx.compose.material.OutlinedTextField androidx.compose.material3.OutlinedTextField
androidx.compose.material.RadioButton androidx.compose.material3.RadioButton
androidx.compose.material.RangeSlider androidx.compose.material3.RangeSlider
androidx.compose.material.Scaffold androidx.compose.material3.Scaffold
androidx.compose.material.ScrollableTabRow androidx.compose.material3.ScrollableTabRow
androidx.compose.material.Slider androidx.compose.material3.Slider
androidx.compose.material.Snackbar androidx.compose.material3.Snackbar
androidx.compose.material.Switch androidx.compose.material3.Switch
androidx.compose.material.Tab androidx.compose.material3.Tab
androidx.compose.material.TabRow androidx.compose.material3.TabRow
androidx.compose.material.Text androidx.compose.material3.Text
androidx.compose.material.TextButton androidx.compose.material3.TextButton
androidx.compose.material.TextField androidx.compose.material3.TextField
androidx.compose.material.TopAppBar androidx.compose.material3.TopAppBar
androidx.compose.material.TriStateCheckbox androidx.compose.material3.TriStateCheckbox

ดูคอมโพเนนต์และเลย์เอาต์ M3 ล่าสุดในภาพรวมข้อมูลอ้างอิงเกี่ยวกับ Compose Material 3 API และคอยติดตามหน้ารุ่นเพื่อดู API ใหม่และที่อัปเดต

Scaffold, Snackbar และลิ้นชักการนำทาง

การเปรียบเทียบสคาฟเฟิล M2 กับ M3 ที่มีแถบนําทางและลิ้นชักการนําทาง
รูปที่ 5 โครงสร้าง M2 ที่มีแถบข้อมูลและลิ้นชักการนำทาง (ซ้าย) เทียบกับโครงสร้าง M3 ที่มีแถบข้อมูลและลิ้นชักการนำทาง (ขวา)

Scaffold ใน M3 แตกต่างจาก M2 ทั้ง M2 และ M3 คอมโพสิชันเลย์เอาต์หลักจะมีชื่อว่า Scaffold แต่แพ็กเกจและพารามิเตอร์การนําเข้าจะแตกต่างกันดังนี้

M2

import androidx.compose.material.Scaffold

Scaffold(
    // M2 scaffold parameters
)

M3

import androidx.compose.material3.Scaffold

Scaffold(
    // M3 scaffold parameters
)

M2 Scaffold มีพารามิเตอร์ backgroundColor ซึ่งตอนนี้เปลี่ยนชื่อเป็น containerColor ใน M3 Scaffold

M2

import androidx.compose.material.Scaffold

Scaffold(
    backgroundColor = …,
    content = { … }
)

M3

import androidx.compose.material3.Scaffold

Scaffold(
    containerColor = …,
    content = { … }
)

คลาส M2 ScaffoldState ไม่มีอยู่ใน M3 อีกต่อไปเนื่องจากมีพารามิเตอร์ drawerState ซึ่งไม่จําเป็นต้องใช้อีกต่อไป หากต้องการแสดงแถบนําทางที่มี M3 Scaffold ให้ใช้ SnackbarHostState แทน

M2

import androidx.compose.material.Scaffold
import androidx.compose.material.rememberScaffoldState

val scaffoldState = rememberScaffoldState()
val scope = rememberCoroutineScope()

Scaffold(
    scaffoldState = scaffoldState,
    content = {
        …
        scope.launch {
            scaffoldState.snackbarHostState.showSnackbar(…)
        }
    }
)

M3

import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState

val snackbarHostState = remember { SnackbarHostState() }
val scope = rememberCoroutineScope()

Scaffold(
    snackbarHost = { SnackbarHost(snackbarHostState) },
    content = {
        …
        scope.launch {
            snackbarHostState.showSnackbar(…)
        }
    }
)

พารามิเตอร์ drawer* ทั้งหมดจาก M2 Scaffold ถูกนําออกจาก M3 Scaffold แล้ว ซึ่งรวมถึงพารามิเตอร์ต่างๆ เช่น drawerShape และ drawerContent หากต้องการแสดงลิ้นชักที่มี M3 Scaffold ให้ใช้คอมโพสิชันลิ้นชักการนำทาง เช่น ModalNavigationDrawer แทน

M2

import androidx.compose.material.DrawerValue
import
import androidx.compose.material.Scaffold
import androidx.compose.material.rememberDrawerState
import androidx.compose.material.rememberScaffoldState

val scaffoldState = rememberScaffoldState(
    drawerState = rememberDrawerState(DrawerValue.Closed)
)
val scope = rememberCoroutineScope()

Scaffold(
    scaffoldState = scaffoldState,
    drawerContent = { … },
    drawerGesturesEnabled = …,
    drawerShape = …,
    drawerElevation = …,
    drawerBackgroundColor = …,
    drawerContentColor = …,
    drawerScrimColor = …,
    content = {
        …
        scope.launch {
            scaffoldState.drawerState.open()
        }
    }
)

M3

import androidx.compose.material3.DrawerValue
import androidx.compose.material3.ModalDrawerSheet
import androidx.compose.material3.ModalNavigationDrawer
import androidx.compose.material3.Scaffold
import androidx.compose.material3.rememberDrawerState

val drawerState = rememberDrawerState(DrawerValue.Closed)
val scope = rememberCoroutineScope()

ModalNavigationDrawer(
    drawerState = drawerState,
    drawerContent = {
        ModalDrawerSheet(
            drawerShape = …,
            drawerTonalElevation = …,
            drawerContainerColor = …,
            drawerContentColor = …,
            content = { … }
        )
    },
    gesturesEnabled = …,
    scrimColor = …,
    content = {
        Scaffold(
            content = {
                …
                scope.launch {
                    drawerState.open()
                }
            }
        )
    }
)

แถบแอปด้านบน

การเปรียบเทียบสคาฟเฟิล M2 กับ M3 ที่มีแถบแอปด้านบนและรายการที่เลื่อนได้
รูปที่ 6 โครงสร้าง M2 ที่มีแถบแอปด้านบนและรายการที่เลื่อนได้ (ซ้าย) เทียบกับโครงสร้าง M3 ที่มีแถบแอปด้านบนและรายการที่เลื่อนได้ (ขวา)

แถบแอปด้านบนใน M3 จะแตกต่างจากใน M2 ทั้ง M2 และ M3 คอมโพสิชันแถบแอปด้านบนหลักจะมีชื่อว่า TopAppBar แต่แพ็กเกจและพารามิเตอร์การนําเข้าจะแตกต่างกัน ดังนี้

M2

import androidx.compose.material.TopAppBar

TopAppBar(…)

M3

import androidx.compose.material3.TopAppBar

TopAppBar(…)

พิจารณาใช้ M3 CenterAlignedTopAppBar หากคุณเคยจัดเนื้อหาให้อยู่ตรงกลางใน M2 TopAppBar คุณควรทราบเกี่ยวกับ MediumTopAppBar และ LargeTopAppBar ด้วย

แถบแอปด้านบนของ M3 มีพารามิเตอร์ scrollBehavior ใหม่เพื่อให้ฟังก์ชันการทำงานที่แตกต่างกันเมื่อเลื่อนผ่านคลาส TopAppBarScrollBehavior เช่น การเปลี่ยนระดับ ซึ่งจะทำงานร่วมกับการเลื่อนเนื้อหาผ่านModifer.nestedScroll ซึ่งทำได้ใน M2 TopAppBar โดยการเปลี่ยนพารามิเตอร์ elevation ด้วยตนเอง ดังนี้

M2

import androidx.compose.material.AppBarDefaults
import androidx.compose.material.Scaffold
import androidx.compose.material.TopAppBar

val state = rememberLazyListState()
val isAtTop by remember {
    derivedStateOf {
        state.firstVisibleItemIndex == 0 && state.firstVisibleItemScrollOffset == 0
    }
}

Scaffold(
    topBar = {
        TopAppBar(
            elevation = if (isAtTop) {
                0.dp
            } else {
                AppBarDefaults.TopAppBarElevation
            },
            …
        )
    },
    content = {
        LazyColumn(state = state) { … }
    }
)

M3

import androidx.compose.material3.Scaffold
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults

val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior()

Scaffold(
    modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
    topBar = {
        TopAppBar(
            scrollBehavior = scrollBehavior,
            …
        )
    },
    content = {
        LazyColumn { … }
    }
)

การไปยังส่วนต่างๆ ด้านล่าง / แถบนำทาง

การเปรียบเทียบการนำทางด้านล่างของ M2 กับแถบนำทางของ M3
รูปที่ 7 การนำทางด้านล่างของ M2 (ซ้าย) เทียบกับแถบนำทางของ M3 (ขวา)

การนำทางด้านล่างใน M2 ได้เปลี่ยนชื่อเป็นแถบนําทางใน M3 ใน M2 มีคอมโพสิเบิล BottomNavigation และ BottomNavigationItem ส่วนใน M3 มีคอมโพสิเบิล NavigationBar และ NavigationBarItem ดังนี้

M2

import androidx.compose.material.BottomNavigation
import androidx.compose.material.BottomNavigationItem

BottomNavigation {
    BottomNavigationItem(…)
    BottomNavigationItem(…)
    BottomNavigationItem(…)
}

M3

import androidx.compose.material3.NavigationBar
import androidx.compose.material3.NavigationBarItem

NavigationBar {
    NavigationBarItem(…)
    NavigationBarItem(…)
    NavigationBarItem(…)
}

ปุ่ม ปุ่มไอคอน และ FAB

การเปรียบเทียบปุ่ม M2 กับ M3
รูปที่ 8 ปุ่ม M2 (ซ้าย) เทียบกับปุ่ม M3 (ขวา)

ปุ่ม ปุ่มไอคอน และปุ่มการทำงานแบบลอย (FAB) ใน M3 จะแตกต่างจากใน M2 M3 มีคอมโพสิชันปุ่ม M2 ทั้งหมดต่อไปนี้

M2

import androidx.compose.material.Button
import androidx.compose.material.ExtendedFloatingActionButton
import androidx.compose.material.FloatingActionButton
import androidx.compose.material.IconButton
import androidx.compose.material.IconToggleButton
import androidx.compose.material.OutlinedButton
import androidx.compose.material.TextButton

// M2 buttons
Button(…)
OutlinedButton(…)
TextButton(…)
// M2 icon buttons
IconButton(…)
IconToggleButton(…)
// M2 FABs
FloatingActionButton(…)
ExtendedFloatingActionButton(…)

M3

import androidx.compose.material3.Button
import androidx.compose.material3.ExtendedFloatingActionButton
import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.IconButton
import androidx.compose.material3.IconToggleButton
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.TextButton

// M3 buttons
Button(…)
OutlinedButton(…)
TextButton(…)
// M3 icon buttons
IconButton(…)
IconToggleButton(…)
// M3 FABs
FloatingActionButton(…)
ExtendedFloatingActionButton(…)

M3 ยังมีปุ่มรูปแบบใหม่ด้วย ดูข้อมูลได้ที่ภาพรวมเอกสารอ้างอิง Compose Material 3 API

เปลี่ยน

การเปรียบเทียบสวิตช์ M2 กับ M3
รูปที่ 9 สวิตช์ M2 (ซ้าย) เทียบกับสวิตช์ M3 (ขวา)

Switch ใน M3 แตกต่างจาก M2 ทั้ง M2 และ M3 จะใช้ชื่อ Switch สำหรับ Switch Composable แต่แพ็กเกจการนําเข้าจะแตกต่างกันดังนี้

M2

import androidx.compose.material.Switch

Switch(…)

M3

import androidx.compose.material3.Switch

Switch(…)

พื้นผิวและระดับความสูง

การเปรียบเทียบระดับผิว M2 กับระดับผิว M3 ในธีมสว่างและธีมมืด
รูปที่ 10 ระดับพื้นผิว M2 เทียบกับระดับพื้นผิว M3 ในธีมสว่าง (ซ้าย) และธีมมืด (ขวา)

ระบบพื้นผิวและระดับความสูงใน M3 จะแตกต่างจาก M2 ระดับความสูงใน M3 มี 2 ประเภท ได้แก่

  • ระดับเงา (ทำให้เกิดเงา เหมือนกับ M2)
  • การปรับโทนสี (วางซ้อนสี ซึ่งเป็นฟีเจอร์ใหม่ใน M3)

ใน "เขียน" การดำเนินการนี้จะมีผลกับฟังก์ชัน M2 Surface และฟังก์ชัน M3 Surface

M2

import androidx.compose.material.Surface

Surface(
    elevation = …
) { … }

M3

import androidx.compose.material3.Surface

Surface(
    shadowElevation = …,
    tonalElevation = …
) { … }

คุณสามารถใช้ค่า elevation Dp ใน M2 สำหรับทั้ง shadowElevation และ/หรือ tonalElevation ใน M3 ทั้งนี้ขึ้นอยู่กับค่ากําหนดการออกแบบ UX/UI Surface คือคอมโพสิเบิลที่รองรับคอมโพเนนต์ส่วนใหญ่ ดังนั้นคอมโพสิเบิลของคอมโพเนนต์จึงอาจแสดงพารามิเตอร์ระดับที่คุณต้องย้ายข้อมูลด้วยวิธีเดียวกัน

การปรับโทนใน M3 เข้ามาแทนที่แนวคิดการวางซ้อนระดับความสูงในธีมมืดของ M2 ด้วยเหตุนี้ ElevationOverlay และ LocalElevationOverlay จึงไม่มีอยู่ใน M3 และ LocalAbsoluteElevation ใน M2 ได้เปลี่ยนเป็น LocalAbsoluteTonalElevation ใน M3

ข้อความไฮไลต์และเนื้อหาอัลฟ่า

การเปรียบเทียบไอคอนและข้อความที่เน้นของ M2 กับ M3
รูปที่ 11 ไอคอน M2 และข้อความที่เน้น (ซ้าย) เทียบกับไอคอน M3 และข้อความที่เน้น (ขวา)

ข้อความไฮไลต์ใน M3 แตกต่างจาก M2 อย่างมีนัยสำคัญ ใน M2 เน้นการใช้สีบนที่มีค่าอัลฟ่าที่เฉพาะเจาะจงเพื่อแยกความแตกต่างของเนื้อหา เช่น ข้อความและไอคอน ใน M3 มี 2 วิธีดังนี้

  • ใช้สีเปิดควบคู่ไปกับสีเปิดแบบต่างๆ จากระบบสี M3 ที่ขยายการให้บริการ
  • การใช้แบบอักษรที่มีน้ำหนักต่างกันสำหรับข้อความ

ด้วยเหตุนี้ ContentAlpha และ LocalContentAlpha จึงไม่มีอยู่ใน M3 และต้องแทนที่

เราขอแนะนำให้ใช้การแมปต่อไปนี้เป็นจุดเริ่มต้น

M2 M3
onSurface กับ ContentAlpha.high onSurface โดยทั่วไป FontWeight.Medium - FontWeight.Black สำหรับข้อความ
onSurface กับ ContentAlpha.medium onSurfaceVariant โดยทั่วไป FontWeight.Thin - FontWeight.Normal สำหรับข้อความ
onSurface กับ ContentAlpha.disabled onSurface.copy(alpha = 0.38f)

ต่อไปนี้คือตัวอย่างการเน้นไอคอนใน M2 เทียบกับ M3

M2

import androidx.compose.material.ContentAlpha
import androidx.compose.material.LocalContentAlpha

// High emphasis
CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.high) {
    Icon(…)
}
// Medium emphasis
CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.medium) {
    Icon(…)
}
// Disabled emphasis
CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.disabled) {
    Icon(…)
}

M3

import androidx.compose.material3.LocalContentColor

// High emphasis
CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.onSurface) {
    Icon(…)
}
// Medium emphasis
CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.onSurfaceVariant) {
    Icon(…)
}
// Disabled emphasis
CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.onSurface.copy(alpha = 0.38f)) {
    Icon(…)
}

ต่อไปนี้คือตัวอย่างการเน้นข้อความใน M2 และ M3

M2

import androidx.compose.material.ContentAlpha
import androidx.compose.material.LocalContentAlpha

// High emphasis
CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.high) {
    Text(…)
}
// Medium emphasis
CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.medium) {
    Text(…)
}
// Disabled emphasis
CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.disabled) {
    Text(…)
}

M3

import androidx.compose.material3.LocalContentColor

// High emphasis
Text(
    …,
    fontWeight = FontWeight.Bold
)
// Medium emphasis
Text(
    …,
    fontWeight = FontWeight.Normal
)
// Disabled emphasis
CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.onSurface.copy(alpha = 0.38f)) {
    Text(
        …,
        fontWeight = FontWeight.Normal
    )
}

พื้นหลังและคอนเทนเนอร์

พื้นหลังใน M2 คือคอนเทนเนอร์ที่มีชื่อใน M3 โดยทั่วไป คุณสามารถแทนที่พารามิเตอร์ background* ใน M2 ด้วย container* ใน M3 โดยใช้ค่าเดียวกัน เช่น

M2

Badge(
    backgroundColor = MaterialTheme.colors.primary
) { … }

M3

Badge(
    containerColor = MaterialTheme.colorScheme.primary
) { … }

ดูข้อมูลเพิ่มเติมเกี่ยวกับการย้ายข้อมูลจาก M2 ไปยัง M3 ใน Compose ได้จากแหล่งข้อมูลเพิ่มเติมต่อไปนี้

เอกสาร

ตัวอย่างแอป

วิดีโอ

เอกสารอ้างอิงและซอร์สโค้ดของ API