การใช้ View ใน Compose

คุณรวมลำดับชั้นของ Android View ไว้ใน UI ของการเขียนได้ วิธีนี้ โดยเฉพาะในกรณีที่คุณต้องการใช้องค์ประกอบ UI ที่ยังไม่มีใน เขียน เช่น AdView วิธีการนี้ยังช่วยให้คุณสามารถนำมุมมองที่กำหนดเองที่คุณอาจออกแบบไว้มาใช้ใหม่ได้ด้วย

หากต้องการรวมองค์ประกอบข้อมูลพร็อพเพอร์ตี้หรือลำดับชั้น ให้ใช้ AndroidView Composable AndroidView ผ่านการตรวจสอบ lambda ที่ส่งกลับ View AndroidView ยังมี update Callback ซึ่งเรียกใช้เมื่อมุมมองขยายออก การจัดองค์ประกอบ AndroidView ใหม่ เมื่อใดก็ตามที่ State อ่านภายใน Callback มีการเปลี่ยนแปลง AndroidView เช่นเดียวกับหลายรายการ Composable ในตัวอื่นๆ จะใช้พารามิเตอร์ Modifier ที่ใช้ได้ เช่น เพื่อกำหนดตำแหน่งใน Composable หลัก

@Composable
fun CustomView() {
    var selectedItem by remember { mutableStateOf(0) }

    // Adds view to Compose
    AndroidView(
        modifier = Modifier.fillMaxSize(), // Occupy the max size in the Compose UI tree
        factory = { context ->
            // Creates view
            MyView(context).apply {
                // Sets up listeners for View -> Compose communication
                setOnClickListener {
                    selectedItem = 1
                }
            }
        },
        update = { view ->
            // View's been inflated or state read in this block has been updated
            // Add logic here if necessary

            // As selectedItem is read here, AndroidView will recompose
            // whenever the state changes
            // Example of Compose -> View communication
            view.selectedItem = selectedItem
        }
    )
}

@Composable
fun ContentExample() {
    Column(Modifier.fillMaxSize()) {
        Text("Look at this CustomView!")
        CustomView()
    }
}

AndroidView พร้อมการเชื่อมโยงมุมมอง

ในการฝังเค้าโครง XML ให้ใช้ AndroidViewBinding API ซึ่งให้บริการโดยไลบรารี androidx.compose.ui:ui-viewbinding ถึง ในกรณีเช่นนี้ โปรเจ็กต์ต้องเปิดใช้การเชื่อมโยงข้อมูลพร็อพเพอร์ตี้

@Composable
fun AndroidViewBindingExample() {
    AndroidViewBinding(ExampleLayoutBinding::inflate) {
        exampleView.setBackgroundColor(Color.GRAY)
    }
}

AndroidView ในรายการแบบ Lazy Loading

หากคุณใช้ AndroidView ในรายการแบบ Lazy Loading (LazyColumn, LazyRow, Pager ฯลฯ) ให้พิจารณาใช้ AndroidView ใช้งานโอเวอร์โหลดในเวอร์ชัน 1.4.0-rc01 โอเวอร์โหลดนี้ทำให้ Compose สามารถใช้ซ้ำได้ อินสแตนซ์ View ที่อยู่ด้านล่างเมื่อมีการใช้การเรียบเรียงที่มีองค์ประกอบซ้ำตามที่เป็น เช่น รายการแบบ Lazy

โอเวอร์โหลดของ AndroidView นี้จะเพิ่มพารามิเตอร์อีก 2 รายการ ได้แก่

  • onReset - มีการเรียกใช้ Callback เพื่อส่งสัญญาณว่า View กำลังจะถูกเรียก ที่ใช้ซ้ำได้ ต้องระบุค่านี้เพื่อเปิดใช้การใช้ข้อมูลพร็อพเพอร์ตี้ซ้ำ
  • onRelease (ไม่บังคับ) - มีการเรียกใช้ Callback เพื่อส่งสัญญาณว่า View มี ออกจากการเรียบเรียงแล้วและจะไม่นำไปใช้ซ้ำอีก

@OptIn(ExperimentalComposeUiApi::class)
@Composable
fun AndroidViewInLazyList() {
    LazyColumn {
        items(100) { index ->
            AndroidView(
                modifier = Modifier.fillMaxSize(), // Occupy the max size in the Compose UI tree
                factory = { context ->
                    MyView(context)
                },
                update = { view ->
                    view.selectedItem = index
                },
                onReset = { view ->
                    view.clear()
                }
            )
        }
    }
}

ส่วนย่อยใน Compose

ใช้ AndroidViewBinding Composable เพื่อเพิ่ม Fragment ใน Compose AndroidViewBinding มีการจัดการเฉพาะส่วนย่อย เช่น การนำพารามิเตอร์ Fragment เมื่อ Composable ออกจากการเรียบเรียง

ซึ่งทำได้ด้วยการเพิ่ม XML ที่มี FragmentContainerView เป็นเจ้าของ Fragment ของคุณ

ตัวอย่างเช่น หากกําหนด my_fragment_layout.xml ไว้ คุณสามารถใช้ ในลักษณะนี้ขณะแทนที่แอตทริบิวต์ XML android:name ด้วย ชื่อชั้นเรียนของ Fragment:

<androidx.fragment.app.FragmentContainerView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/fragment_container_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:name="com.example.compose.snippets.interop.MyFragment" />

ขยายส่วนย่อยนี้ใน Compose ดังนี้

@Composable
fun FragmentInComposeExample() {
    AndroidViewBinding(MyFragmentLayoutBinding::inflate) {
        val myFragment = fragmentContainerView.getFragment<MyFragment>()
        // ...
    }
}

หากต้องการใช้ส่วนย่อยหลายรายการในเลย์เอาต์เดียวกัน ให้ตรวจสอบว่ามี กำหนดรหัสที่ไม่ซ้ำกันสำหรับแต่ละ FragmentContainerView

การเรียกใช้เฟรมเวิร์ก Android จาก Compose

Compose จะทำงานภายในคลาสเฟรมเวิร์กของ Android ตัวอย่างเช่น มีการโฮสต์ ในคลาส Android View เช่น Activity หรือ Fragment และอาจใช้ Android คลาสของเฟรมเวิร์ก เช่น Context, ทรัพยากรของระบบ Service หรือ BroadcastReceiver

ดูข้อมูลเพิ่มเติมเกี่ยวกับทรัพยากรของระบบได้ที่ทรัพยากรใน Compose

การเรียบเรียงท้องถิ่น

CompositionLocal คลาสอนุญาตให้ส่งข้อมูลโดยปริยายผ่านฟังก์ชัน Composable คือ ซึ่งปกติแล้วจะมีค่าในโหนดใดโหนดหนึ่งของโครงสร้าง UI ค่าดังกล่าวสามารถ ใช้โดยองค์ประกอบสืบทอดที่ประกอบกันได้โดยไม่ต้องประกาศ CompositionLocal เป็นพารามิเตอร์ในฟังก์ชัน Composable

ใช้ CompositionLocal เพื่อเผยแพร่ค่าสำหรับประเภทเฟรมเวิร์ก Android ใน Compose เช่น Context, Configuration หรือ View ที่มีการเขียน จะใช้โฮสต์กับ LocalContext, LocalConfiguration หรือ LocalView โปรดทราบว่าชั้นเรียน CompositionLocal จะมี Local นำหน้าเพื่อประสิทธิภาพที่ดีขึ้น การค้นพบได้ด้วยการใช้การเติมข้อความอัตโนมัติใน IDE

เข้าถึงค่าปัจจุบันของ CompositionLocal โดยใช้ current ตัวอย่างเช่น โค้ดด้านล่างแสดงข้อความโทสต์โดยการระบุ LocalContext.current ลงในเมธอด Toast.makeToast

@Composable
fun ToastGreetingButton(greeting: String) {
    val context = LocalContext.current
    Button(onClick = {
        Toast.makeText(context, greeting, Toast.LENGTH_SHORT).show()
    }) {
        Text("Greet")
    }
}

ดูตัวอย่างที่สมบูรณ์มากขึ้นได้จากกรณีศึกษา: BroadcastReceivers ที่ตอนท้ายของ เอกสาร

การโต้ตอบอื่นๆ

หากไม่มีการกำหนดยูทิลิตีไว้สำหรับการโต้ตอบที่คุณต้องการ แนวทางปฏิบัติที่ดีที่สุด คือการปฏิบัติตามหลักเกณฑ์ทั่วไปของการเขียน ข้อมูลไหลลง เหตุการณ์ไหลขึ้น (กล่าวถึงมากขึ้นในการคิด ใน Compose) ตัวอย่างเช่น Composable นี้ เปิดกิจกรรมอื่น เช่น

class OtherInteractionsActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // get data from savedInstanceState
        setContent {
            MaterialTheme {
                ExampleComposable(data, onButtonClick = {
                    startActivity(Intent(this, MyActivity::class.java))
                })
            }
        }
    }
}

@Composable
fun ExampleComposable(data: DataExample, onButtonClick: () -> Unit) {
    Button(onClick = onButtonClick) {
        Text(data.title)
    }
}

กรณีศึกษา: Broadcast Receiver

สำหรับตัวอย่างฟีเจอร์ที่ใช้ได้จริงมากขึ้น คุณอาจต้องการย้ายข้อมูลหรือติดตั้งใช้งาน ในการเขียน และแสดง CompositionLocal และ ด้านข้าง ของเอฟเฟกต์ สมมติว่า BroadcastReceiver ต้องลงทะเบียนจาก ฟังก์ชันที่ประกอบกันได้

โซลูชันนี้จะใช้ LocalContext เพื่อใช้บริบทปัจจุบัน และ ผลข้างเคียงของ rememberUpdatedState และ DisposableEffect

@Composable
fun SystemBroadcastReceiver(
    systemAction: String,
    onSystemEvent: (intent: Intent?) -> Unit
) {
    // Grab the current context in this part of the UI tree
    val context = LocalContext.current

    // Safely use the latest onSystemEvent lambda passed to the function
    val currentOnSystemEvent by rememberUpdatedState(onSystemEvent)

    // If either context or systemAction changes, unregister and register again
    DisposableEffect(context, systemAction) {
        val intentFilter = IntentFilter(systemAction)
        val broadcast = object : BroadcastReceiver() {
            override fun onReceive(context: Context?, intent: Intent?) {
                currentOnSystemEvent(intent)
            }
        }

        context.registerReceiver(broadcast, intentFilter)

        // When the effect leaves the Composition, remove the callback
        onDispose {
            context.unregisterReceiver(broadcast)
        }
    }
}

@Composable
fun HomeScreen() {

    SystemBroadcastReceiver(Intent.ACTION_BATTERY_CHANGED) { batteryStatus ->
        val isCharging = /* Get from batteryStatus ... */ true
        /* Do something if the device is charging */
    }

    /* Rest of the HomeScreen */
}

ขั้นตอนถัดไป

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