ข้อมูลเบื้องต้นเกี่ยวกับเลย์เอาต์ของการเขียน

Jetpack Compose ช่วยให้การออกแบบและสร้าง UI ของแอปง่ายขึ้นมาก เขียน เปลี่ยนรูปแบบสถานะเป็นองค์ประกอบ UI ผ่าน:

  1. การจัดวางองค์ประกอบ
  2. การจัดวางองค์ประกอบ
  3. ภาพวาดองค์ประกอบ

เขียนสถานะการเปลี่ยนรูปแบบเป็น UI ผ่านการจัดองค์ประกอบ เลย์เอาต์ ภาพวาด

เอกสารนี้เน้นที่การจัดวางองค์ประกอบ โดยอธิบายบางส่วนของสิ่งปลูกสร้าง Compose บล็อกจะช่วยให้คุณสามารถจัดวางองค์ประกอบ UI ของคุณ

เป้าหมายของเลย์เอาต์ใน Compose

การใช้ระบบเลย์เอาต์ของ Jetpack Compose มีเป้าหมายหลัก 2 ประการ ดังนี้

พื้นฐานของฟังก์ชันที่ประกอบกันได้

ฟังก์ชันที่ประกอบกันได้เป็นองค์ประกอบพื้นฐานของการเขียน Composable คือฟังก์ชันที่ปล่อย Unit ซึ่งอธิบาย UI บางส่วนของคุณ จะรับอินพุตและสร้างสิ่งที่แสดงบนหน้าจอ สำหรับข้อมูลเพิ่มเติม เกี่ยวกับ Composable โปรดดูที่บทความ รูปแบบต่อไปนี้

ฟังก์ชัน Composable อาจปล่อยองค์ประกอบ UI หลายรายการ แต่ถ้าคุณไม่ ให้แนวทางในการจัดเรียงข้อความ Compose อาจจัดเรียง องค์ประกอบบางอย่างในลักษณะที่คุณไม่ต้องการ ตัวอย่างเช่น โค้ดนี้จะสร้างข้อความสองข้อความ องค์ประกอบ:

@Composable
fun ArtistCard() {
    Text("Alfred Sisley")
    Text("3 minutes ago")
}

Compose จะซ้อนองค์ประกอบข้อความโดยไม่มีคำแนะนำเกี่ยวกับวิธีที่คุณต้องการจัดเรียงข้อความ ทับกัน ซึ่งทำให้อ่านไม่ได้

องค์ประกอบข้อความ 2 อย่างที่วาดทับกัน ทำให้อ่านข้อความไม่ได้

Compose มีคอลเล็กชันเลย์เอาต์ที่พร้อมใช้งานเพื่อช่วยคุณในการจัดเรียง องค์ประกอบ UI และช่วยให้กำหนดเลย์เอาต์ที่มีความพิเศษเฉพาะตัวของคุณได้ง่ายขึ้น

คอมโพเนนต์เลย์เอาต์มาตรฐาน

ในหลายกรณี คุณสามารถใช้เพียงเลย์เอาต์มาตรฐานของ Compose องค์ประกอบ

ใช้ Column เพื่อวางรายการในแนวตั้งบนหน้าจอ

@Composable
fun ArtistCardColumn() {
    Column {
        Text("Alfred Sisley")
        Text("3 minutes ago")
    }
}

องค์ประกอบข้อความ 2 รายการจัดเรียงในเลย์เอาต์แบบคอลัมน์เพื่อให้อ่านข้อความได้ง่าย

ในทำนองเดียวกัน ให้ใช้ Row เพื่อวางรายการในแนวนอนบนหน้าจอ ทั้งการสนับสนุนของ Column และ Row โดยกำหนดค่าการปรับแนวขององค์ประกอบที่มีอยู่

@Composable
fun ArtistCardRow(artist: Artist) {
    Row(verticalAlignment = Alignment.CenterVertically) {
        Image(bitmap = artist.image, contentDescription = "Artist image")
        Column {
            Text(artist.name)
            Text(artist.lastSeenOnline)
        }
    }
}

แสดงเลย์เอาต์ที่ซับซ้อนขึ้นโดยมีกราฟิกเล็กๆ อยู่ข้างคอลัมน์ขององค์ประกอบข้อความ

ใช้ Box เพื่อวางองค์ประกอบทับองค์ประกอบอื่น นอกจากนี้ Box ยังรองรับการกำหนดค่าการปรับแนวที่เจาะจงขององค์ประกอบที่อยู่ภายในด้วย

@Composable
fun ArtistAvatar(artist: Artist) {
    Box {
        Image(bitmap = artist.image, contentDescription = "Artist image")
        Icon(Icons.Filled.Check, contentDescription = "Check mark")
    }
}

แสดงองค์ประกอบ 2 รายการซ้อนกัน

โดยทั่วไปแล้ว องค์ประกอบเหล่านี้คือสิ่งที่คุณต้องการ คุณเขียนฟังก์ชันที่ประกอบกันได้เพื่อรวมเลย์เอาต์เหล่านี้เข้าด้วยกันเป็นเลย์เอาต์ที่ซับซ้อนมากขึ้นที่เหมาะกับแอปได้

เปรียบเทียบ Composable ของเลย์เอาต์พื้นฐาน 3 รายการ ได้แก่ คอลัมน์ แถว และกล่อง

หากต้องการกำหนดตำแหน่งของบุตรหลานภายใน Row ให้ตั้งค่า horizontalArrangement และ verticalAlignment อาร์กิวเมนต์ สำหรับ Column ให้ตั้งค่า verticalArrangement และ horizontalAlignment อาร์กิวเมนต์:

@Composable
fun ArtistCardArrangement(artist: Artist) {
    Row(
        verticalAlignment = Alignment.CenterVertically,
        horizontalArrangement = Arrangement.End
    ) {
        Image(bitmap = artist.image, contentDescription = "Artist image")
        Column { /*...*/ }
    }
}

จัดรายการไว้ทางด้านขวา

โมเดลเลย์เอาต์

ในรูปแบบเลย์เอาต์ แผนผัง UI จะวางอยู่ในบัตรผ่านครั้งเดียว แต่ละโหนด จะวัดผลตัวเองก่อน จากนั้นจึงวัดเด็กซ้ำๆ ผ่าน จำกัดขนาดต้นไม้ให้เด็กได้ โหนดใบไม้ก็จะมีขนาดและ ด้วยขนาดที่แก้ไขแล้วและคำแนะนำตำแหน่งในตำแหน่งที่ส่งคืน ต้นไม้

ใช้เวลาสั้นๆ ผู้ปกครองวัดผลก่อนบุตรหลาน แต่มีขนาดและวางหลัง บุตรหลานของตน

ลองพิจารณาฟังก์ชัน SearchResult ต่อไปนี้

@Composable
fun SearchResult() {
    Row {
        Image(
            // ...
        )
        Column {
            Text(
                // ...
            )
            Text(
                // ...
            )
        }
    }
}

ฟังก์ชันนี้จะแสดงโครงสร้าง UI ต่อไปนี้

SearchResult
  Row
    Image
    Column
      Text
      Text

ในตัวอย่าง SearchResult เลย์เอาต์แบบต้นไม้ UI จะเป็นไปตามลำดับต่อไปนี้

  1. ระบบขอให้วัดโหนดรูท Row
  2. โหนดราก Row ขอให้โหนดย่อยแรก Image ทำการวัด
  3. Image เป็นโหนดย่อย (ไม่มีโหนดย่อย) จึงรายงานขนาด และแสดงผลคำแนะนำตำแหน่ง
  4. โหนดราก Row ขอให้โหนดย่อยลำดับที่ 2 ซึ่งก็คือ Column วัดค่า
  5. โหนด Column ขอให้วัดย่อย Text รายการแรก
  6. โหนด Text แรกคือโหนด Leaf จึงรายงานขนาดและแสดงผล คำแนะนำตำแหน่ง
  7. โหนด Column ขอให้วัดย่อย Text รายการที่ 2
  8. โหนด Text ที่ 2 เป็นโหนด Leaf จึงรายงานขนาดและแสดงผล คำแนะนำตำแหน่ง
  9. เมื่อโหนด Column วัด ปรับขนาด และวางโหนดย่อยแล้ว สามารถกำหนดขนาดและตำแหน่งของตัวเอง
  10. เมื่อโหนดราก Row ได้วัด ปรับขนาด และวางโหนดย่อยแล้ว สามารถกำหนดขนาดและตำแหน่งของตัวเอง

การเรียงลำดับการวัด ขนาด และการวางตำแหน่งในแผนผัง UI ของผลการค้นหา

ประสิทธิภาพ

การเขียนสามารถมีประสิทธิภาพสูงโดยการวัดผลเด็กเพียงครั้งเดียว บัตรผ่านเดียว การวัดนั้นดีสำหรับประสิทธิภาพ ทำให้ Compose สามารถจัดการ แผนผัง UI หากองค์ประกอบหนึ่งวัดย่อย 2 ครั้งและองค์ประกอบย่อยนั้นวัดแต่ละรายการ ประมาณ 2 ครั้ง และต่อๆ ไป ความพยายามเพียงครั้งเดียวในการจัดวาง UI ทั้งหมด ทำงานหนัก ทำให้แอปมีประสิทธิภาพอยู่เสมอ

หากเลย์เอาต์ต้องใช้การวัดหลายแบบด้วยเหตุผลบางประการ Compose จะมี ระบบพิเศษ การวัดภายใน คุณอ่านเพิ่มเติมเกี่ยวกับฟีเจอร์นี้ได้ ในการวัดภายในใน Compose Layouts

เนื่องจากการวัดและการวางตำแหน่งเป็นช่วงย่อยที่แตกต่างกันของการส่งผ่านเลย์เอาต์ สามารถทำการเปลี่ยนแปลงที่มีผลต่อตำแหน่งของรายการเท่านั้น ไม่ใช่การวัด แยกกัน

การใช้ตัวแก้ไขในเลย์เอาต์

ตามที่อธิบายไว้ในตัวปรับแต่ง Compose คุณสามารถใช้ คีย์ตัวปรับแต่งเพื่อตกแต่งหรือเพิ่ม Composable ตัวปรับแต่งเป็นสิ่งสำคัญ ในการปรับแต่งเลย์เอาต์ ตัวอย่างเช่น ตรงนี้เรารวมตัวปรับแต่งหลายรายการ เพื่อปรับแต่ง ArtistCard:

@Composable
fun ArtistCardModifiers(
    artist: Artist,
    onClick: () -> Unit
) {
    val padding = 16.dp
    Column(
        Modifier
            .clickable(onClick = onClick)
            .padding(padding)
            .fillMaxWidth()
    ) {
        Row(verticalAlignment = Alignment.CenterVertically) { /*...*/ }
        Spacer(Modifier.size(padding))
        Card(
            elevation = CardDefaults.cardElevation(defaultElevation = 4.dp),
        ) { /*...*/ }
    }
}

การจัดวางที่ยังคงมีความซับซ้อนมากขึ้น โดยใช้คีย์ตัวปรับแต่งเพื่อเปลี่ยนวิธีจัดเรียงกราฟิกและพื้นที่ที่ตอบสนองต่ออินพุตของผู้ใช้

ในโค้ดข้างต้น คุณสังเกตเห็นฟังก์ชันของตัวปรับแต่งต่างๆ ที่ใช้งานร่วมกัน

  • clickable สร้างการตอบสนองที่ประกอบกันได้ต่อข้อมูลจากผู้ใช้ และแสดงระลอกคลื่น
  • padding วางพื้นที่รอบๆ องค์ประกอบ
  • fillMaxWidth ทำให้ Composable เติมความกว้างสูงสุดตามที่กำหนดไว้จาก ระดับบนสุด
  • size() จะระบุความกว้างและความสูงที่ต้องการขององค์ประกอบ

เลย์เอาต์แบบเลื่อนได้

ดูข้อมูลเพิ่มเติมเกี่ยวกับเลย์เอาต์แบบเลื่อนได้ใน เขียนเอกสารประกอบเกี่ยวกับท่าทางสัมผัส

สำหรับรายการและลิสต์แบบ Lazy Loading โปรดดูที่ เขียนเอกสารประกอบเกี่ยวกับรายการ

เลย์เอาต์ที่ปรับเปลี่ยนตามอุปกรณ์

เลย์เอาต์ควรออกแบบโดยคำนึงถึงการวางแนวหน้าจอที่แตกต่างกัน และขนาดของอุปกรณ์ เขียนข้อเสนอเริ่มต้น 2-3 กลไกในการ ช่วยปรับเลย์เอาต์ที่ประกอบกันได้ให้เข้ากับการกำหนดค่าหน้าจอในลักษณะต่างๆ

ข้อจำกัด

เพื่อให้ทราบข้อจำกัดที่มาจากองค์ประกอบระดับบนสุดและออกแบบเลย์เอาต์ คุณสามารถใช้ BoxWithConstraints ได้ การวัดผล ข้อจำกัด ได้ในขอบเขตของเนื้อหา lambda คุณสามารถใช้การวัดเหล่านี้ได้ ข้อจำกัดในการเขียนรูปแบบที่แตกต่างกันสำหรับการกำหนดค่าหน้าจอที่แตกต่างกัน

@Composable
fun WithConstraintsComposable() {
    BoxWithConstraints {
        Text("My minHeight is $minHeight while my maxWidth is $maxWidth")
    }
}

เลย์เอาต์แบบอิงตามช่อง

Compose มี Composable จำนวนมากโดยอิงตาม Material ออกแบบด้วย ทรัพยากร Dependency androidx.compose.material:material (รวมไว้เมื่อสร้าง Compose Project ใน Android Studio) เพื่อช่วยให้การสร้าง UI เป็นเรื่องง่าย องค์ประกอบเช่น Drawer FloatingActionButton, และ TopAppBar ได้รับการระบุทั้งหมด

คอมโพเนนต์ Material มีการใช้ slot API เป็นจำนวนมาก ซึ่งเป็นการนำเสนอรูปแบบ Compose ใน เพื่อเพิ่มเลเยอร์ของการปรับแต่งทับ Composable วิธีนี้ทำให้ มีความยืดหยุ่นมากกว่า เนื่องจากจะยอมรับองค์ประกอบย่อยที่สามารถกำหนดค่า โดยไม่ต้องแสดงพารามิเตอร์การกำหนดค่าทั้งหมดของหน่วยย่อย ช่องจะปล่อยพื้นที่ว่างใน UI ไว้เพื่อให้นักพัฒนาแอปป้อนข้อมูลได้ตามต้องการ สำหรับ ตัวอย่างเช่น ช่องเหล่านี้คือช่องที่คุณสามารถปรับแต่งใน TopAppBar:

แผนภาพแสดงสล็อตที่พร้อมใช้งานในแถบแอป Material Component

คำสั่ง Composable มักจะใช้ lambda ที่ประกอบกันได้ content ( content: @Composable () -> Unit) Slot API แสดงพารามิเตอร์ content หลายรายการสำหรับการใช้งานที่เฉพาะเจาะจง ตัวอย่างเช่น TopAppBar อนุญาตให้คุณระบุเนื้อหาสำหรับ title navigationIcon และ actions

ตัวอย่างเช่น Scaffold ช่วยให้คุณใช้ UI ด้วยโครงสร้างเลย์เอาต์แบบดีไซน์ Material ได้ Scaffoldมีช่องสำหรับคอมโพเนนต์ Material ระดับบนสุดที่พบได้บ่อยที่สุด เช่น TopAppBar BottomAppBar, FloatingActionButton และ Drawer โดยการใช้ Scaffold คุณสามารถตรวจสอบว่าคอมโพเนนต์เหล่านี้อยู่ในตำแหน่งที่ถูกต้องและ ทำงานร่วมกันอย่างถูกต้อง

แอปตัวอย่าง JetNews ที่ใช้ Scaffold ในการวางตำแหน่งองค์ประกอบหลายรายการ

@Composable
fun HomeScreen(/*...*/) {
    ModalNavigationDrawer(drawerContent = { /* ... */ }) {
        Scaffold(
            topBar = { /*...*/ }
        ) { contentPadding ->
            // ...
        }
    }
}