Korzystanie z widoków w sekcji Utwórz

W interfejsie Compose możesz uwzględnić hierarchię widoków Androida. To podejście jest szczególnie przydatne, jeśli chcesz używać elementów interfejsu, które nie są jeszcze dostępne w Compose, takich jak AdView. To podejście pozwala też ponownie używać utworzonych widoków niestandardowych.

Aby uwzględnić element widoku lub hierarchię, użyj funkcji kompozycyjnej AndroidView . Do funkcji AndroidView przekazywane jest wyrażenie lambda, które zwraca View. AndroidView udostępnia też wywołanie zwrotne update, które jest wywoływane, gdy widok jest rozwijany. Funkcja AndroidView jest rekomponowana za każdym razem, gdy zmienia się wartość State odczytywana w wywołaniu zwrotnym. AndroidView, podobnie jak wiele innych wbudowanych funkcji kompozycyjnych, przyjmuje parametr Modifier, który może służyć na przykład do ustawiania pozycji w nadrzędnej funkcji kompozycyjnej.

@Composable
fun CustomView() {
    var selectedItem by remember { mutableIntStateOf(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 z powiązaniem widoku

Aby umieścić układ XML, użyj interfejsu API AndroidViewBinding, który jest udostępniany przez bibliotekę androidx.compose.ui:ui-viewbinding. Aby to zrobić, musisz włączyć w projekcie wiązanie widoku.

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

AndroidView w listach Lazy

Jeśli używasz AndroidView na liście Lazy (LazyColumn, LazyRow, Pager itd.), rozważ użycie przeciążenia AndroidView wprowadzonego w wersji 1.4.0-rc01. To przeciążenie umożliwia Compose ponowne użycie bazowej instancji View, gdy zawierająca ją kompozycja jest używana ponownie, jak w przypadku list Lazy.

To przeciążenie metody AndroidView dodaje 2 dodatkowe parametry:

  • onReset – wywołanie zwrotne, które informuje, że View zostanie ponownie użyty. Aby włączyć ponowne użycie widoku, ta wartość nie może być pusta.
  • onRelease (opcjonalnie) – wywołanie zwrotne, które sygnalizuje, że element View został usunięty z kompozycji i nie będzie już używany.

@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()
                }
            )
        }
    }
}

Fragmenty w Compose (etap przejściowy)

Aby dodać Fragment w Compose, użyj funkcji kompozycyjnej AndroidFragment. AndroidFragment obsługuje fragmenty w specyficzny sposób, np. usuwa fragment, gdy funkcja kompozycyjna opuszcza kompozycję.

Aby uwzględnić fragment, użyj funkcji kompozycyjnej AndroidFragment. Przekazujesz klasę Fragment do AndroidFragment, która następnie dodaje instancję tej klasy bezpośrednio do kompozycji. AndroidFragment udostępnia też obiekt fragmentState do tworzenia AndroidFragment z danym stanem, arguments do przekazania do nowego fragmentu i wywołanie zwrotne onUpdate, które udostępnia fragment z kompozycji. Podobnie jak wiele innych wbudowanych funkcji kompozycyjnych, AndroidFragment akceptuje parametr Modifier, którego możesz użyć na przykład do ustawienia jej pozycji w nadrzędnej funkcji kompozycyjnej.

Wywołaj AndroidFragment w Compose w ten sposób:

@Composable
fun FragmentInComposeExample() {
    AndroidFragment<MyFragment>()
}

Stan cyklu życia fragmentu limitu

We fragmencie 1.9.0 i nowszych możesz użyć parametru maxLifecycle, aby ograniczyć stan cyklu życia umieszczonego elementu Fragment.

Na przykład w elemencie HorizontalPager możesz dynamicznie ustawić maxLifecycle na RESUMED tylko wtedy, gdy odpowiednia strona jest aktywna, i utrzymywać strony poza ekranem na poziomie STARTED. Gdy użytkownik przechodzi na inną stronę, limit fragmentów na poprzedniej stronie wynosi STARTED. Spowoduje to wstrzymanie lub anulowanie zadań w zakresie RESUMED (np. współprogramów działających w repeatOnLifecycle(RESUMED)), co uniemożliwi stronom poza ekranem wykonywanie zadań tylko na pierwszym planie, zachowując jednocześnie ich interfejs zainicjowany w stanie STARTED:

HorizontalPager(state = pagerState) { page ->
    // Dynamically cap the lifecycle state based on whether the page is selected
    val maxLifecycle = if (pagerState.settledPage == page) {
        Lifecycle.State.RESUMED
    } else {
        Lifecycle.State.STARTED
    }

    when (page) {
        0 -> AndroidFragment<HomeFragment>(maxLifecycle = maxLifecycle)
        1 -> AndroidFragment<LibraryFragment>(maxLifecycle = maxLifecycle)
        /* Other pages and corresponding fragments */
    }
}

Wywoływanie platformy Androida z Compose

Compose działa w ramach klas platformy Androida. Na przykład jest hostowany w klasach widoku Androida, takich jak Activity lub Fragment, i może używać klas platformy Androida, takich jak Context, zasoby systemowe, Service lub BroadcastReceiver.

Więcej informacji o zasobach systemowych znajdziesz w artykule Zasoby w Compose.

Lokalne kompozycje

Klasy CompositionLocal umożliwiają niejawne przekazywanie danych przez funkcje typu „composable”. Zwykle są one dostarczane z wartością w określonym węźle drzewa interfejsu. Ta wartość może być używana przez elementy podrzędne funkcji typu „composable” bez deklarowania CompositionLocal jako parametru w funkcji typu „composable”.

CompositionLocal służy do propagowania wartości typów platformy Androida w Compose, takich jak Context, Configuration lub View, w których kod Compose jest hostowany z odpowiednim LocalContext, LocalConfiguration lub LocalView. Pamiętaj, że klasy CompositionLocal są poprzedzone prefiksem Local, aby ułatwić ich znajdowanie za pomocą autouzupełniania w IDE.

Dostęp do bieżącej wartości CompositionLocal można uzyskać za pomocą właściwości current. Na przykład poniższy kod wyświetla wyskakujące powiadomienie, przekazując LocalContext.current do metody Toast.makeToast.

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

Odbiorniki komunikatów

Aby zaprezentować CompositionLocal i efekty uboczne, jeśli BroadcastReceiver musi zostać zarejestrowany z funkcji typu „composable”, użyj LocalContext, aby użyć bieżącego kontekstu, oraz efektów ubocznych rememberUpdatedState i 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 */
}

Inne interakcje

Jeśli nie ma zdefiniowanego narzędzia do interakcji, której potrzebujesz, najlepiej postępować zgodnie z ogólnymi wytycznymi dotyczącymi Compose: dane przepływają w dół, zdarzenia przepływają w górę (więcej informacji znajdziesz w artykule Myślenie w Compose). Na przykład ten element kompozycyjny uruchamia inną aktywność:

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)
    }
}