หน้านี้แสดงภาพรวมระดับสูงของเลเยอร์สถาปัตยกรรมที่ประกอบขึ้นเป็น Jetpack Compose และหลักการสำคัญที่ใช้ในการออกแบบนี้
Jetpack Compose ไม่ใช่โปรเจ็กต์แบบโมโนลิธิกเดียว แต่สร้างขึ้นจากโมดูลจำนวนหนึ่งที่ประกอบเข้าด้วยกันเพื่อสร้างสแต็กที่สมบูรณ์ การทำความเข้าใจโมดูลต่างๆ ที่ประกอบกันเป็น Jetpack Compose จะช่วยให้คุณทำสิ่งต่อไปนี้ได้
- ใช้ระดับนามธรรมที่เหมาะสมเพื่อสร้างแอปหรือไลบรารี
- ทำความเข้าใจว่าเมื่อใดที่คุณสามารถ "ลดระดับ" ไปยังระดับที่ต่ำลงเพื่อการควบคุมหรือการปรับแต่งที่มากขึ้น
- ลดทรัพยากร Dependency
เลเยอร์
เลเยอร์หลักของ Jetpack Compose มีดังนี้
รูปที่ 1 เลเยอร์หลักของ Jetpack Compose
แต่ละเลเยอร์สร้างขึ้นจากระดับที่ต่ำกว่า โดยรวมฟังก์ชันการทำงานเพื่อสร้างคอมโพเนนต์ระดับที่สูงขึ้น แต่ละเลเยอร์จะสร้างขึ้นบน API สาธารณะของเลเยอร์ที่ต่ำกว่าเพื่อยืนยันขอบเขตของโมดูล และช่วยให้คุณแทนที่เลเยอร์ใดก็ได้หากจำเป็น มาดูเลเยอร์เหล่านี้จากล่างขึ้นบนกัน
- รันไทม์
- โมดูลนี้มีพื้นฐานของรันไทม์ Compose เช่น
remember,mutableStateOf, คำอธิบายประกอบ@ComposableและSideEffectคุณอาจพิจารณาสร้างโดยตรงบนเลเยอร์นี้หากต้องการเพียงความสามารถในการจัดการต้นไม้ของ Compose ไม่ใช่ UI - UI
- เลเยอร์ UI ประกอบด้วยหลายโมดูล (
ui-text,ui-graphics,ui-toolingฯลฯ) โมดูลเหล่านี้ใช้พื้นฐานของชุดเครื่องมือ UI เช่นLayoutNode,Modifier, ตัวแฮนเดิลอินพุต, เลย์เอาต์ที่กำหนดเอง และการวาด คุณอาจพิจารณาสร้างต่อยอดจากเลเยอร์นี้หากต้องการเพียงแนวคิดพื้นฐานของชุดเครื่องมือ UI เท่านั้น - Foundation
- โมดูลนี้มีองค์ประกอบพื้นฐานที่ไม่ขึ้นอยู่กับระบบการออกแบบสำหรับ Compose UI เช่น
RowและColumn,LazyColumn, การจดจำท่าทางสัมผัสบางอย่าง เป็นต้น คุณอาจพิจารณาสร้างระบบการออกแบบของคุณเองโดยต่อยอดจากเลเยอร์พื้นฐาน - วัสดุ
- โมดูลนี้ใช้ระบบการออกแบบ Material Design สำหรับ Compose UI โดยมีระบบการกำหนดธีม คอมโพเนนต์ที่มีสไตล์ การแสดงผลริปเปิล และไอคอน สร้างต่อยอดจากเลเยอร์นี้เมื่อใช้ Material Design ในแอป
หลักการออกแบบ
หลักการชี้นำสำหรับ Jetpack Compose คือการจัดเตรียมฟังก์ชันการทำงานขนาดเล็กที่มุ่งเน้นซึ่งสามารถประกอบ (หรือเขียน) เข้าด้วยกัน แทนที่จะเป็นคอมโพเนนต์แบบโมโนลิธิกเพียงไม่กี่รายการ แนวทางนี้มีข้อดีหลายประการ
ควบคุม
คอมโพเนนต์ระดับสูงมักจะทำงานให้คุณได้มากกว่า แต่จะจำกัดปริมาณการควบคุมโดยตรงที่คุณมี หากต้องการควบคุมมากขึ้น คุณสามารถ "เลื่อนลง" เพื่อใช้คอมโพเนนต์ระดับต่ำกว่าได้
เช่น หากต้องการสร้างภาพเคลื่อนไหวให้กับสีของคอมโพเนนต์ คุณอาจใช้ API animateColorAsState ดังนี้
val color = animateColorAsState(if (condition) Color.Green else Color.Red)
อย่างไรก็ตาม หากคุณต้องการให้คอมโพเนนต์เริ่มต้นเป็นสีเทาเสมอ คุณจะทำไม่ได้ด้วย API นี้ แต่คุณสามารถใช้ API ระดับต่ำกว่าแทนได้ ดังนี้
Animatable
val color = remember { Animatable(Color.Gray) } LaunchedEffect(condition) { color.animateTo(if (condition) Color.Green else Color.Red) }
API ระดับสูงกว่า animateColorAsState สร้างขึ้นจาก API ระดับต่ำกว่า Animatable การใช้ API ระดับต่ำกว่าจะซับซ้อนกว่าแต่ให้การควบคุมมากกว่า เลือกระดับของนามธรรมที่เหมาะกับความต้องการของคุณมากที่สุด
การปรับแต่ง
การประกอบคอมโพเนนต์ระดับสูงขึ้นจากองค์ประกอบที่เล็กลงจะช่วยให้ปรับแต่งคอมโพเนนต์ได้ง่ายขึ้นมากหากจำเป็น ตัวอย่างเช่น ลองพิจารณาการใช้งาน Button ที่เลเยอร์ Material มีให้
@Composable fun Button( // … content: @Composable RowScope.() -> Unit ) { Surface(/* … */) { CompositionLocalProvider(/* … */) { // set LocalContentAlpha ProvideTextStyle(MaterialTheme.typography.button) { Row( // … content = content ) } } } }
Button ประกอบขึ้นจาก 4 คอมโพเนนต์ ได้แก่
วัสดุ
Surfaceที่ให้พื้นหลัง รูปร่าง การจัดการการคลิก ฯลฯCompositionLocalProviderซึ่งจะเปลี่ยนอัลฟาของเนื้อหาเมื่อเปิดหรือปิดใช้ปุ่มProvideTextStyleจะตั้งค่ารูปแบบข้อความเริ่มต้นที่จะใช้Rowมีนโยบายเลย์เอาต์เริ่มต้นสำหรับเนื้อหาของปุ่ม
เราได้ละเว้นพารามิเตอร์และความคิดเห็นบางส่วนเพื่อให้โครงสร้างชัดเจนขึ้น แต่คอมโพเนนต์ทั้งหมดมีโค้ดเพียงประมาณ 40 บรรทัดเท่านั้น เนื่องจากเป็นเพียงการประกอบคอมโพเนนต์ 4 รายการนี้เพื่อใช้ปุ่ม คอมโพเนนต์อย่าง Button
มีแนวคิดที่ชัดเจนเกี่ยวกับพารามิเตอร์ที่แสดง โดยสร้างสมดุลระหว่างการเปิดใช้การปรับแต่งทั่วไปกับการเพิ่มขึ้นอย่างรวดเร็วของพารามิเตอร์ที่อาจทำให้คอมโพเนนต์ใช้งานยากขึ้น ตัวอย่างเช่น คอมโพเนนต์ Material มีการปรับแต่งที่ระบุไว้ในระบบการออกแบบ Material Design ซึ่งช่วยให้ปฏิบัติตามหลักการของ Material Design ได้ง่าย
อย่างไรก็ตาม หากต้องการปรับแต่งนอกเหนือจากพารามิเตอร์ของคอมโพเนนต์ คุณสามารถ "เลื่อนลง" ไปยังระดับหนึ่งและแยกคอมโพเนนต์ได้ เช่น Material Design ระบุว่าปุ่มควรมีพื้นหลังสีทึบ หากต้องการพื้นหลังแบบไล่ระดับสี พารามิเตอร์ Button จะไม่รองรับตัวเลือกนี้ ในกรณีนี้ คุณสามารถใช้การติดตั้งใช้งาน Material Button เป็นข้อมูลอ้างอิงและสร้างคอมโพเนนต์ของคุณเองได้ ดังนี้
@Composable fun GradientButton( // … background: List<Color>, modifier: Modifier = Modifier, content: @Composable RowScope.() -> Unit ) { Row( // … modifier = modifier .clickable(onClick = {}) .background( Brush.horizontalGradient(background) ) ) { CompositionLocalProvider(/* … */) { // set material LocalContentAlpha ProvideTextStyle(MaterialTheme.typography.button) { content() } } } }
การติดตั้งใช้งานข้างต้นยังคงใช้คอมโพเนนต์จากเลเยอร์ Material เช่น แนวคิดของ Material เกี่ยวกับอัลฟ่าของเนื้อหาปัจจุบันและรูปแบบข้อความปัจจุบัน อย่างไรก็ตาม ระบบจะแทนที่ Surface ของวัสดุด้วย Row และจัดรูปแบบเพื่อให้ได้รูปลักษณ์ที่ต้องการ
หากไม่ต้องการใช้แนวคิด Material เลย เช่น หากสร้างระบบการออกแบบที่กำหนดเอง คุณสามารถเลือกใช้เฉพาะคอมโพเนนต์เลเยอร์พื้นฐานได้ ดังนี้
@Composable fun BespokeButton( // … backgroundColor: Color, modifier: Modifier = Modifier, content: @Composable RowScope.() -> Unit ) { Row( // … modifier = modifier .clickable(onClick = {}) .background(backgroundColor) ) { // No Material components used content() } }
Jetpack Compose จะสงวนชื่อที่ง่ายที่สุดไว้สำหรับคอมโพเนนต์ระดับสูงสุด ตัวอย่างเช่น
androidx.compose.material.Text
สร้างขึ้นจาก
androidx.compose.foundation.text.BasicText
ซึ่งจะช่วยให้คุณสามารถระบุการติดตั้งใช้งานของคุณเองด้วยชื่อที่ค้นพบได้มากที่สุด หากต้องการแทนที่ระดับที่สูงขึ้น
การเลือก Abstraction ที่เหมาะสม
ปรัชญาของ Compose ในการสร้างคอมโพเนนต์ที่นำกลับมาใช้ใหม่ได้แบบเป็นเลเยอร์หมายความว่าคุณไม่ควรใช้ Building Block ระดับต่ำเสมอไป คอมโพเนนต์ระดับสูงจำนวนมากไม่เพียงแต่มีฟังก์ชันการทำงานที่มากกว่าเท่านั้น แต่ยังมักใช้แนวทางปฏิบัติแนะนำ เช่น การรองรับการช่วยเหลือพิเศษด้วย
ตัวอย่างเช่น หากต้องการเพิ่มการรองรับท่าทางสัมผัสลงในคอมโพเนนต์ที่กำหนดเอง คุณสามารถสร้างคอมโพเนนต์นี้ตั้งแต่ต้นโดยใช้ Modifier.pointerInput แต่ก็มีคอมโพเนนต์ระดับสูงอื่นๆ ที่สร้างขึ้นจากคอมโพเนนต์นี้ซึ่งอาจเป็นจุดเริ่มต้นที่ดีกว่า เช่น Modifier.draggable, Modifier.scrollable หรือ Modifier.swipeable
ตามกฎแล้ว คุณควรสร้างบนคอมโพเนนต์ระดับสูงสุดซึ่งมีฟังก์ชันการทำงานที่คุณต้องการ เพื่อให้ได้รับประโยชน์จากแนวทางปฏิบัติแนะนำที่รวมอยู่ด้วย
ดูข้อมูลเพิ่มเติม
ดูตัวอย่าง Jetsnack เพื่อดูตัวอย่างการสร้างระบบการออกแบบที่กำหนดเอง
แนะนำสำหรับคุณ
- หมายเหตุ: ข้อความลิงก์จะแสดงเมื่อ JavaScript ปิดอยู่
- Kotlin สำหรับ Jetpack Compose
- รายการและตารางกริด
- ผลข้างเคียงใน Compose