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

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

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

แนวทาง

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

การขึ้นต่อกัน

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

คลัง แพ็กเกจและเวอร์ชัน
ไอคอน Compose Material androidx.compose.material:material-icons-*:$m2-version
การกระเพื่อมของเนื้อหา 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 แตกต่างกัน ใน Compose การตั้งค่านี้จะมีผลกับคลาส 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 Theme Builder เพื่อสร้างรูปแบบสี M3 แทน ใช้สี M2 เป็นสีต้นฉบับหลักในเครื่องมือ ซึ่งเครื่องมือจะขยายเป็นจานสีแบบโทนสีที่ใช้โดยรูปแบบสี M3 เราขอแนะนำให้ใช้การแมปต่อไปนี้เป็น จุดเริ่มต้น

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

คุณสามารถคัดลอกค่ารหัสสีแบบเลขฐาน 16 สำหรับธีมสว่างและธีมมืดจากเครื่องมือ และใช้เพื่อติดตั้งใช้งานอินสแตนซ์ ColorScheme ของ M3 หรือ 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
        
    }
}

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

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

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

การพิมพ์

การเปรียบเทียบระบบการพิมพ์ M2 และ M3
รูปที่ 3 ระบบการพิมพ์ M3 (ซ้าย) เทียบกับระบบการพิมพ์ M2 (ขวา)

ระบบการพิมพ์ใน M3 แตกต่างจาก M2 จำนวนพารามิเตอร์การจัดรูปแบบข้อความจะเท่ากันโดยประมาณ แต่มีชื่อต่างกันและแมปกับคอมโพเนนต์ M3 ต่างกัน ใน Compose จะมีผลกับคลาส 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 แตกต่างกัน ใน Compose จะมีผลกับคลาส 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 ใหม่ และ 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
)

ตอนนี้พารามิเตอร์ backgroundColor ใน M2 Scaffold เปลี่ยนชื่อเป็น 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 ซึ่งไม่จำเป็นอีกต่อไป หากต้องการแสดงแถบข้อความพร้อมScaffoldของ M3 ให้ใช้ 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 ให้ใช้ Composable ของลิ้นชักการนำทาง เช่น 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 เช่น การเปลี่ยนระดับความสูง ซึ่งจะทำงานร่วมกับเนื้อหาที่เลื่อนได้โดยใช้ Modifier.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 (ขวา)

เราได้เปลี่ยนชื่อ Bottom Navigation ใน M2 เป็นแถบนำทางใน M3 ใน M2 มี Composable BottomNavigation และ BottomNavigationItem ส่วนใน M3 มี Composable 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 ยังมีปุ่มรูปแบบใหม่ด้วย ดูได้ที่ภาพรวมเอกสารอ้างอิง API ของ Compose Material 3

เปลี่ยน

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

Switch ใน M3 แตกต่างจาก M2 ใน M2 และ M3 สวิตช์ ที่ใช้ร่วมกันได้มีชื่อว่า Switch แต่แพ็กเกจการนำเข้าจะแตกต่างกัน ดังนี้

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 และซอร์สโค้ด