Jetpack Compose มีการใช้งาน Material Design ซึ่งเป็นระบบการออกแบบที่ครอบคลุมสำหรับการสร้างอินเทอร์เฟซดิจิทัล คอมโพเนนต์ Material Design (ปุ่ม การ์ด สวิตช์ และอื่นๆ) สร้างขึ้นจากการกำหนดธีม Material ซึ่งเป็นวิธีที่เป็นระบบในการปรับแต่ง Material Design เพื่อให้แสดงถึงแบรนด์ของผลิตภัณฑ์ได้ดียิ่งขึ้น ธีม Material ประกอบด้วยแอตทริบิวต์สี การจัดพิมพ์ และรูปร่าง เมื่อคุณปรับแต่งแอตทริบิวต์เหล่านี้ การเปลี่ยนแปลงจะแสดงในคอมโพเนนต์ที่คุณใช้สร้างแอปโดยอัตโนมัติ
Jetpack Compose ใช้แนวคิดเหล่านี้กับ Composable MaterialTheme ดังนี้
MaterialTheme( colors = // ... typography = // ... shapes = // ... ) { // app content }
กำหนดค่าพารามิเตอร์ที่คุณส่งไปยัง MaterialTheme เพื่อกำหนดธีมของแอปพลิเคชัน
สี
สีจะได้รับการจำลองใน Compose ด้วยคลาส Color ซึ่งเป็นคลาสที่เก็บข้อมูล
val Red = Color(0xffff0000) val Blue = Color(red = 0f, green = 0f, blue = 1f)
แม้ว่าคุณจะจัดระเบียบสิ่งเหล่านี้ได้ตามต้องการ (เป็นค่าคงที่ระดับบนสุด ภายในซิงเกิลตัน หรือกำหนดแบบอินไลน์) แต่เราขอแนะนำอย่างยิ่งให้ระบุสีในธีมและดึงสีจากธีมนั้น วิธีนี้ช่วยให้รองรับธีมมืดและธีมที่ฝังได้
Compose มีคลาส Colors เพื่อจำลองระบบสี Material Colors มีฟังก์ชัน Builder เพื่อสร้างชุดสีอ่อนหรือเข้ม ดังนี้
private val Yellow200 = Color(0xffffeb46) private val Blue200 = Color(0xff91a4fc) // ... private val DarkColors = darkColors( primary = Yellow200, secondary = Blue200, // ... ) private val LightColors = lightColors( primary = Yellow500, primaryVariant = Yellow400, secondary = Blue700, // ... )
หลังจากกำหนด Colors แล้ว คุณสามารถส่งต่อไปยัง MaterialTheme ได้โดยทำดังนี้
MaterialTheme( colors = if (darkTheme) DarkColors else LightColors ) { // app content }
ใช้สีธีม
คุณสามารถดึงข้อมูล Colors ที่ระบุไว้ใน Composable MaterialTheme ได้โดยใช้ MaterialTheme.colors
Text( text = "Hello theming", color = MaterialTheme.colors.primary )
สีของพื้นผิวและเนื้อหา
คอมโพเนนต์จำนวนมากยอมรับคู่สีและสีของเนื้อหา ดังนี้
Surface( color = MaterialTheme.colors.surface, contentColor = contentColorFor(color), // ... ) { /* ... */ } TopAppBar( backgroundColor = MaterialTheme.colors.primarySurface, contentColor = contentColorFor(backgroundColor), // ... ) { /* ... */ }
ซึ่งไม่เพียงช่วยให้คุณกำหนดสีของ Composable ได้เท่านั้น แต่ยังกำหนดสีเริ่มต้นสำหรับเนื้อหา ซึ่งก็คือ Composable ที่อยู่ภายในได้ด้วย Composable จำนวนมากใช้สีเนื้อหานี้โดยค่าเริ่มต้น เช่น Text จะใช้สีตามสีเนื้อหาขององค์ประกอบหลัก และ Icon จะใช้สีนั้นเพื่อตั้งค่าสีอ่อน
เมธอด contentColorFor() จะดึงข้อมูลสี "เปิด" ที่เหมาะสมสำหรับสีธีมใดๆ ตัวอย่างเช่น หากคุณตั้งค่าสีพื้นหลัง primary ใน Surface ระบบจะใช้ฟังก์ชันนี้เพื่อตั้งค่า onPrimary เป็นสีของเนื้อหา
หากตั้งค่าสีพื้นหลังที่ไม่ใช่ธีม คุณควรระบุสีเนื้อหาที่เหมาะสมด้วย ใช้ LocalContentColor เพื่อดึงสีเนื้อหาที่ต้องการสำหรับพื้นหลังปัจจุบัน ณ ตำแหน่งที่ระบุในลำดับชั้น
Content alpha
บ่อยครั้งที่คุณต้องการปรับเปลี่ยนระดับการเน้นเนื้อหาเพื่อสื่อสารความสำคัญและสร้างลำดับชั้นของภาพ คำแนะนำเกี่ยวกับความอ่านง่ายของข้อความใน Material Design แนะนำให้ใช้ระดับความทึบแสงที่แตกต่างกันเพื่อสื่อถึงระดับความสำคัญที่แตกต่างกัน
Jetpack Compose จะใช้ LocalContentAlpha เพื่อดำเนินการนี้ คุณสามารถระบุอัลฟ่าของเนื้อหาสำหรับลำดับชั้นได้โดยระบุค่าสำหรับ CompositionLocal นี้ Composable ที่ฝังอยู่จะใช้ค่านี้เพื่อใช้การจัดการอัลฟากับเนื้อหาได้ เช่น Text และ Icon จะใช้ชุดค่าผสมของ LocalContentColor โดยค่าเริ่มต้น ซึ่งปรับให้ใช้ LocalContentAlpha Material ระบุค่าอัลฟ่ามาตรฐานบางค่า (high, medium, disabled) ซึ่งจำลองโดยออบเจ็กต์ ContentAlpha
// By default, both Icon & Text use the combination of LocalContentColor & // LocalContentAlpha. De-emphasize content by setting content alpha CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.medium) { Text( // ... ) } CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.disabled) { Icon( // ... ) Text( // ... ) }
ดูข้อมูลเพิ่มเติมเกี่ยวกับ CompositionLocal ได้ที่ข้อมูลที่กำหนดขอบเขตในเครื่องด้วย CompositionLocal
ContentAlpha.high บรรทัดที่ 2 มีข้อมูลเมตาที่มีความสำคัญน้อยกว่า จึงใช้ ContentAlpha.mediumธีมมืด
ใน Compose คุณใช้ธีมสว่างและธีมมืดได้โดยระบุชุด Colors ที่แตกต่างกันให้กับ Composable MaterialTheme ดังนี้
@Composable fun MyTheme( darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit ) { MaterialTheme( colors = if (darkTheme) DarkColors else LightColors, /*...*/ content = content ) }
ในตัวอย่างนี้ MaterialTheme จะรวมอยู่ในฟังก์ชันที่ประกอบกันได้ของตัวเอง ซึ่งยอมรับพารามิเตอร์ที่ระบุว่าจะใช้ธีมมืดหรือไม่ ในกรณีนี้ ฟังก์ชันจะได้รับค่าเริ่มต้นสำหรับ darkTheme โดยการค้นหาการตั้งค่าธีมของอุปกรณ์
คุณสามารถใช้โค้ดลักษณะนี้เพื่อตรวจสอบว่า Colors ปัจจุบันเป็นแบบสว่างหรือมืด
val isLightTheme = MaterialTheme.colors.isLight Icon( painterResource( id = if (isLightTheme) { R.drawable.ic_sun_24 } else { R.drawable.ic_moon_24 } ), contentDescription = "Theme" )
การซ้อนทับระดับความสูง
ใน Material พื้นผิวในธีมมืดที่มีระดับความสูงมากกว่าจะได้รับการวางซ้อนระดับความสูง ซึ่งจะทำให้พื้นหลังสว่างขึ้น ยิ่งระดับความสูงของพื้นผิวสูงขึ้น (ยกขึ้นใกล้กับแหล่งกำเนิดแสงโดยนัยมากขึ้น) พื้นผิวนั้นก็จะยิ่งสว่างขึ้น
Surface Composable จะใช้การวางซ้อนเหล่านี้โดยอัตโนมัติเมื่อใช้สีเข้ม และ Composable ของ Material อื่นๆ ที่ใช้พื้นผิวก็เช่นกัน
Surface( elevation = 2.dp, color = MaterialTheme.colors.surface, // color will be adjusted for elevation /*...*/ ) { /*...*/ }
surface เป็นพื้นหลัง เนื่องจากการ์ดและแถบการไปยังส่วนต่างๆ ด้านล่างอยู่ในระดับความสูงที่แตกต่างกันเหนือพื้นหลัง จึงมีสีที่แตกต่างกันเล็กน้อย โดยการ์ดจะสว่างกว่าพื้นหลัง และแถบการไปยังส่วนต่างๆ ด้านล่างจะสว่างกว่าการ์ดสำหรับสถานการณ์ที่กำหนดเองซึ่งไม่เกี่ยวข้องกับ Surface ให้ใช้ LocalElevationOverlay ซึ่งเป็น CompositionLocal ที่มี ElevationOverlay ที่คอมโพเนนต์ Surface ใช้ ดังนี้
// Elevation overlays // Implemented in Surface (and any components that use it) val color = MaterialTheme.colors.surface val elevation = 4.dp val overlaidColor = LocalElevationOverlay.current?.apply( color, elevation )
หากต้องการปิดใช้การวางซ้อนระดับความสูง ให้ระบุ null ณ จุดที่เลือกในลำดับชั้นที่ประกอบกันได้ ดังนี้
MyTheme { CompositionLocalProvider(LocalElevationOverlay provides null) { // Content without elevation overlays } }
สีเฉพาะจุดที่จำกัด
Material แนะนำให้ใช้สีเฉพาะจุดแบบจำกัดสำหรับธีมมืด โดยเลือกใช้สี surface แทนสี primary ในกรณีส่วนใหญ่ คอมโพสิเบิล Material เช่น TopAppBar และ BottomNavigation จะใช้ลักษณะการทำงานนี้โดยค่าเริ่มต้น
สำหรับสถานการณ์ที่กำหนดเอง ให้ใช้พร็อพเพอร์ตี้ส่วนขยาย primarySurface ดังนี้
Surface( // Switches between primary in light theme and surface in dark theme color = MaterialTheme.colors.primarySurface, /*...*/ ) { /*...*/ }
การพิมพ์
Material กำหนดระบบประเภท ซึ่งส่งเสริมให้คุณใช้รูปแบบที่มีชื่อตามความหมายจำนวนเล็กน้อย
Compose ใช้ระบบประเภทกับคลาส Typography, TextStyle และที่เกี่ยวข้องกับแบบอักษร ตัวสร้าง Typography มีค่าเริ่มต้นสำหรับแต่ละสไตล์ คุณจึงละเว้นสไตล์ที่ไม่ต้องการปรับแต่งได้
val raleway = FontFamily( Font(R.font.raleway_regular), Font(R.font.raleway_medium, FontWeight.W500), Font(R.font.raleway_semibold, FontWeight.SemiBold) ) val myTypography = Typography( h1 = TextStyle( fontFamily = raleway, fontWeight = FontWeight.W300, fontSize = 96.sp ), body1 = TextStyle( fontFamily = raleway, fontWeight = FontWeight.W600, fontSize = 16.sp ) /*...*/ ) MaterialTheme(typography = myTypography, /*...*/) { /*...*/ }
หากต้องการใช้แบบตัวพิมพ์เดียวกันตลอด ให้ระบุพารามิเตอร์ defaultFontFamily และละเว้น fontFamily ขององค์ประกอบ TextStyle ใดๆ ดังนี้
val typography = Typography(defaultFontFamily = raleway) MaterialTheme(typography = typography, /*...*/) { /*...*/ }
ใช้รูปแบบข้อความ
องค์ประกอบ TextStyle เข้าถึงได้โดยใช้ MaterialTheme.typography ดึงข้อมูลองค์ประกอบ TextStyle ดังนี้
Text( text = "Subtitle2 styled", style = MaterialTheme.typography.subtitle2 )
รูปร่าง
Material กำหนดระบบรูปร่าง ซึ่งช่วยให้คุณกำหนดรูปร่างสำหรับคอมโพเนนต์ขนาดใหญ่ กลาง และเล็กได้
Compose ใช้ระบบรูปร่างกับคลาส Shapes ซึ่งช่วยให้คุณระบุ CornerBasedShape สำหรับหมวดหมู่ขนาดแต่ละหมวดหมู่ได้
val shapes = Shapes( small = RoundedCornerShape(percent = 50), medium = RoundedCornerShape(0f), large = CutCornerShape( topStart = 16.dp, topEnd = 0.dp, bottomEnd = 0.dp, bottomStart = 16.dp ) ) MaterialTheme(shapes = shapes, /*...*/) { /*...*/ }
คอมโพเนนต์จำนวนมากใช้รูปร่างเหล่านี้โดยค่าเริ่มต้น เช่น Button, TextField และ FloatingActionButton จะมีค่าเริ่มต้นเป็นขนาดเล็ก AlertDialog จะมีค่าเริ่มต้นเป็นขนาดกลาง และ ModalDrawer จะมีค่าเริ่มต้นเป็นขนาดใหญ่ ดูการแมปทั้งหมดได้ที่ข้อมูลอ้างอิงรูปแบบรูปร่าง
ใช้รูปร่าง
องค์ประกอบ Shape เข้าถึงได้โดยใช้ MaterialTheme.shapes ดึงข้อมูลองค์ประกอบ Shape ด้วยโค้ดดังนี้
Surface( shape = MaterialTheme.shapes.medium, /*...*/ ) { /*...*/ }
รูปแบบเริ่มต้น
Compose ไม่มีแนวคิดที่เทียบเท่ากับสไตล์เริ่มต้นจาก Android Views คุณสามารถใช้ฟังก์ชันการทำงานที่คล้ายกันได้โดยสร้างฟังก์ชันที่ประกอบกันได้ overload ของคุณเองซึ่งรวมคอมโพเนนต์ Material ไว้ด้วย เช่น หากต้องการสร้างรูปแบบปุ่ม ให้รวมปุ่มไว้ในฟังก์ชันที่ประกอบกันได้ของคุณเอง โดยตั้งค่าพารามิเตอร์ที่ต้องการหรือจำเป็นต้องแก้ไขโดยตรง และแสดงพารามิเตอร์อื่นๆ เป็นพารามิเตอร์สำหรับ Composable ที่มีอยู่
@Composable fun MyButton( onClick: () -> Unit, modifier: Modifier = Modifier, content: @Composable RowScope.() -> Unit ) { Button( colors = ButtonDefaults.buttonColors( backgroundColor = MaterialTheme.colors.secondary ), onClick = onClick, modifier = modifier, content = content ) }
การวางซ้อนธีม
คุณสามารถใช้การวางซ้อนธีมที่เทียบเท่าจาก Android Views ใน Compose ได้โดยการฝังคอมโพสิเบิล MaterialTheme เนื่องจาก MaterialTheme จะกำหนดค่าเริ่มต้นของสี ตัวพิมพ์ และรูปร่างเป็นค่าธีมปัจจุบัน พารามิเตอร์อื่นๆ ทั้งหมดจะยังคงใช้ค่าเริ่มต้นเมื่อธีมตั้งค่าพารามิเตอร์เพียงรายการเดียวเท่านั้น
นอกจากนี้ เมื่อย้ายข้อมูลหน้าจอที่อิงตาม View ไปยัง Compose ให้ระวังการใช้แอตทริบิวต์ android:theme คุณอาจต้องใช้ MaterialTheme ใหม่ในส่วนนั้นของแผนผัง UI ของ Compose
ในตัวอย่างนี้ หน้าจอรายละเอียดใช้ PinkTheme สำหรับหน้าจอส่วนใหญ่ และใช้ BlueTheme สำหรับส่วนที่เกี่ยวข้อง ภาพหน้าจอและโค้ดต่อไปนี้แสดงแนวคิดนี้
@Composable fun DetailsScreen(/* ... */) { PinkTheme { // other content RelatedSection() } } @Composable fun RelatedSection(/* ... */) { BlueTheme { // content } }
สถานะส่วนประกอบ
คอมโพเนนต์ Material ที่โต้ตอบได้ (คลิก สลับ ฯลฯ) อาจอยู่ในสถานะภาพที่แตกต่างกัน สถานะต่างๆ ได้แก่ เปิดใช้ ปิดใช้ กด ฯลฯ
คอมโพสิเบิลมักมีพารามิเตอร์ enabled การตั้งค่าเป็น false จะป้องกันการโต้ตอบ และเปลี่ยนพร็อพเพอร์ตี้ เช่น สีและระดับความสูง เพื่อสื่อถึงสถานะของคอมโพเนนต์ด้วยภาพ
enabled = true (ซ้าย) และ enabled = false (ขวา)ในกรณีส่วนใหญ่ คุณสามารถใช้ค่าเริ่มต้นสำหรับค่าต่างๆ เช่น สีและระดับความสูง หากต้องการกำหนดค่าที่ใช้ในสถานะต่างๆ ก็มีคลาสและฟังก์ชันอำนวยความสะดวกให้ใช้งาน ลองพิจารณาตัวอย่างปุ่มต่อไปนี้
Button( onClick = { /* ... */ }, enabled = true, // Custom colors for different states colors = ButtonDefaults.buttonColors( backgroundColor = MaterialTheme.colors.secondary, disabledBackgroundColor = MaterialTheme.colors.onBackground .copy(alpha = 0.2f) .compositeOver(MaterialTheme.colors.background) // Also contentColor and disabledContentColor ), // Custom elevation for different states elevation = ButtonDefaults.elevation( defaultElevation = 8.dp, disabledElevation = 2.dp, // Also pressedElevation ) ) { /* ... */ }
enabled = true (ซ้าย) และ enabled = false (ขวา) พร้อมค่าสีและระดับความสูงที่ปรับแล้วระลอกคลื่น
คอมโพเนนต์ Material ใช้เอฟเฟกต์ริปเปิลเพื่อระบุว่ามีการโต้ตอบกับคอมโพเนนต์นั้นๆ หากคุณใช้ MaterialTheme ในลำดับชั้น ระบบจะใช้ Ripple เป็น Indication เริ่มต้นภายในตัวแก้ไข เช่น clickable และ indication
ในกรณีส่วนใหญ่ คุณสามารถใช้ Ripple เริ่มต้นได้ หากต้องการกำหนดค่าลักษณะที่ปรากฏ คุณสามารถใช้ RippleTheme เพื่อเปลี่ยนพร็อพเพอร์ตี้ เช่น สีและอัลฟ่า
คุณสามารถขยาย RippleTheme และใช้ฟังก์ชันยูทิลิตี defaultRippleColor และ defaultRippleAlpha ได้ จากนั้นคุณสามารถระบุธีม Ripple ที่กำหนดเองในลำดับชั้นโดยใช้ LocalRippleTheme ดังนี้
@Composable fun MyApp() { MaterialTheme { CompositionLocalProvider( LocalRippleTheme provides SecondaryRippleTheme ) { // App content } } } @Immutable private object SecondaryRippleTheme : RippleTheme { @Composable override fun defaultColor() = RippleTheme.defaultRippleColor( contentColor = MaterialTheme.colors.secondary, lightTheme = MaterialTheme.colors.isLight ) @Composable override fun rippleAlpha() = RippleTheme.defaultRippleAlpha( contentColor = MaterialTheme.colors.secondary, lightTheme = MaterialTheme.colors.isLight ) }
RippleConfigurationดูข้อมูลเพิ่มเติม
หากต้องการดูข้อมูลเพิ่มเติมเกี่ยวกับการกำหนดธีม Material ใน Compose โปรดดูแหล่งข้อมูลเพิ่มเติมต่อไปนี้
Codelab
วิดีโอ
แนะนำสำหรับคุณ
- หมายเหตุ: ข้อความลิงก์จะแสดงเมื่อ JavaScript ปิดอยู่
- ระบบการออกแบบที่กำหนดเองใน Compose
- ย้ายข้อมูลจาก Material 2 ไปยัง Material 3 ใน Compose
- การช่วยเหลือพิเศษใน Compose