Jetpack Compose มีการติดตั้งใช้งาน Material Design ซึ่งเป็นระบบการออกแบบที่ครอบคลุมสำหรับการสร้างอินเทอร์เฟซดิจิทัล คอมโพเนนต์ Material Design (ปุ่ม การ์ด สวิตช์ และอื่นๆ) สร้างขึ้นจากการกำหนดธีม Material ซึ่งเป็นวิธีที่เป็นระบบในการ ปรับแต่ง Material Design เพื่อให้สอดคล้องกับแบรนด์ของผลิตภัณฑ์ได้ดียิ่งขึ้น Material Theme มีแอตทริบิวต์สี การพิมพ์ และ รูปร่าง เมื่อปรับแต่งแอตทริบิวต์เหล่านี้ การเปลี่ยนแปลงจะแสดงในคอมโพเนนต์ที่คุณใช้สร้างแอปโดยอัตโนมัติ
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)
แม้ว่าคุณจะจัดระเบียบค่าคงที่เหล่านี้ได้ตามต้องการ (เป็นค่าคงที่ระดับบนสุด ภายใน Singleton หรือกำหนดแบบอินไลน์) แต่เราขอแนะนำให้ระบุสีใน ธีมและดึงสีจากที่นั่น วิธีนี้ช่วยให้รองรับธีมมืดและธีมที่ซ้อนกันได้
Compose มีคลาส Colors เพื่อสร้างโมเดลระบบสี Material Colors มีฟังก์ชันตัวสร้างเพื่อสร้างชุดสีอ่อนหรือเข้ม ดังนี้
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 ที่ส่งไปยัง MaterialTheme Composable ได้โดย
ใช้ 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 ที่อยู่ในนั้นได้ด้วย Composables หลายรายการใช้สีเนื้อหานี้โดยค่าเริ่มต้น เช่น Text จะอิงIconสีตามสีเนื้อหาขององค์ประกอบหลัก และใช้สีนั้นเพื่อกำหนดเฉดสีของตัวเอง
เมธอด contentColorFor() จะดึงสี "เปิด" ที่เหมาะสมสำหรับ
สีธีมใดก็ได้ เช่น หากคุณตั้งค่าสีพื้นหลัง primary ใน
Surface ฟังก์ชันนี้จะใช้เพื่อตั้งค่า onPrimary เป็นสีเนื้อหา
หากตั้งค่าสีพื้นหลังที่ไม่ใช่ธีม คุณควรระบุ
สีเนื้อหาที่เหมาะสมด้วย ใช้ LocalContentColor เพื่อดึงสีเนื้อหาที่ต้องการ
สำหรับพื้นหลังปัจจุบัน ณ ตำแหน่งที่กำหนดในลำดับชั้น
อัลฟ่าของเนื้อหา
บ่อยครั้งที่คุณต้องการเปลี่ยนระดับการเน้นเนื้อหาเพื่อสื่อถึงความสำคัญ และจัดลำดับชั้นของภาพ คำแนะนำด้านความสามารถในการอ่านข้อความของ 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 ในกรณีส่วนใหญ่
Composable ของ 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 Constructor
มีค่าเริ่มต้นสำหรับแต่ละสไตล์ คุณจึงละเว้นสไตล์ที่ไม่ต้องการปรับแต่งได้
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 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 ได้โดยการซ้อน Composable ของ MaterialTheme เนื่องจาก
MaterialTheme จะตั้งค่าเริ่มต้นของสี ตัวอักษร และรูปร่างเป็นค่าธีมปัจจุบัน
พารามิเตอร์อื่นๆ ทั้งหมดจึงยังคงมีค่าเริ่มต้นเมื่อธีมตั้งค่าพารามิเตอร์เหล่านั้นเพียง 1 รายการ
นอกจากนี้ เมื่อย้ายข้อมูลหน้าจอที่อิงตาม View ไปยัง Compose ให้ระวังการใช้งาน
แอตทริบิวต์ android:theme คุณอาจต้องใช้ MaterialTheme
ในส่วนนั้นของโครงสร้าง UI ของ Compose
ในตัวอย่างนี้ หน้าจอรายละเอียดใช้ PinkTheme สำหรับส่วนใหญ่ของหน้าจอ
และใช้ BlueTheme สำหรับส่วนที่เกี่ยวข้อง ภาพหน้าจอและโค้ดต่อไปนี้แสดงแนวคิดนี้
@Composable fun DetailsScreen(/* ... */) { PinkTheme { // other content RelatedSection() } } @Composable fun RelatedSection(/* ... */) { BlueTheme { // content } }
สถานะของคอมโพเนนต์
คอมโพเนนต์ Material ที่โต้ตอบได้ (คลิก เปิด/ปิด ฯลฯ) อาจมีสถานะภาพที่แตกต่างกัน สถานะต่างๆ ได้แก่ เปิดใช้ ปิดใช้ กด ฯลฯ
โดย Composables มักจะมีพารามิเตอร์ 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 ) }
RippleThemeดูข้อมูลเพิ่มเติม
ดูข้อมูลเพิ่มเติมเกี่ยวกับ Material Theming ใน Compose ได้จากแหล่งข้อมูลเพิ่มเติมต่อไปนี้
Codelabs
วิดีโอ
แนะนำสำหรับคุณ
- หมายเหตุ: ข้อความลิงก์จะแสดงเมื่อ JavaScript ปิดอยู่
- ระบบการออกแบบที่กำหนดเองใน Compose
- ย้ายข้อมูลจาก Material 2 ไปยัง Material 3 ใน Compose
- การช่วยเหลือพิเศษใน Compose