ย้ายข้อมูลจาก 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 ได้อย่างสมบูรณ์หรือไม่ มีสถานการณ์เกี่ยวกับ blocker บางกรณีที่ควรตรวจสอบก่อนเริ่มดำเนินการ ดังนี้

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

นั่งร้าน แถบแสดงข้อความ และลิ้นชักการนำทาง

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

การยกระดับโทนสีใน 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