This article aims to provide an overview of the different APIs available for developers to integrate composables
in Fragments
and vice versa.
We will cover the following topics
- Composable in
XML-based Fragment
- Full
content
of the fragment as Composable - Using Fragment in Compose-based UI —
AndroidViewBinding
- Using Fragment in Compose-based UI —
AndroidViewFragment
- Using Composables directly with
Navigation library
Composable in XML-based Fragment
- Layout file
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/coordinator_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.compose.ui.platform.ComposeView
android:id="@+id/hello_compose_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
- Accessing
ComposeView from Kotlin-based Activity or Fragment
class FragmentWithComposable : Fragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
val rootView: View = inflater.inflate(R.layout.fragment_with_composable, container, false)
rootView.findViewById<ComposeView>(R.id.hello_compose_view).apply {
setContent {
YourAppTheme {
Text("Hello from Composable")
}
}
}
return rootView
}
}
You can also use
viewBinding instead of
findViewById
Multiple composables
- When we want to use multiple composables, we must add an
ID to each composable.
- Define IDs in
res/values/ids.xml file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item name="compose_view_1" type="id" />
<item name="compose_view_1" type="id" />
</resources>
class ExFragmentMultipleComposeView : Fragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View = LinearLayout(requireContext()).apply {
addView(
ComposeView(requireContext()).apply {
setViewCompositionStrategy(
ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed
)
id = R.id.compose_view_1
// ...
}
)
addView(TextView(requireContext()))
addView(
ComposeView(requireContext()).apply {
setViewCompositionStrategy(
ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed
)
id = R.id.compose_view_1
// ...
}
)
}
}
Fragment with full Compose based UI — ComposeView
- Manually set the
view composition strategy and then
set the content
class BlankFragment : Fragment() {
var uri: Uri? = null
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
return ComposeView(requireContext()).apply {
// Dispose of the Composition when the view's LifecycleOwner is destroyed
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
setContent {
MaterialTheme {
// In Compose world
HomeScreen()
}
}
}
}
}
2. Fragment — content extension
function
It’s available starting with version 1.7.0 of fragment via
f
ragment-compose artifact
Add dependency to your project. Here is an example of using the Version catalog
fragmentKtx = "1.8.4"
androidx-fragment-compose = { module = "androidx.fragment:fragment-compose", version.ref = "fragmentKtx" }
- In your module’s
build.gradle
file
implementation(libs.androidx.fragment.compose)
- Code of
content function
fun Fragment.content(content: @Composable () -> Unit): ComposeView {
return ComposeView(requireContext()).apply {
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
setContent(content)
}
}
As you can see it handles the setting of view composition strategy and it takes content as
Composable
and call setContent internally for us.
class FragmentWithContentExt : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View = content {
Column(modifier = Modifier
.fillMaxSize()
.systemBarsPadding()) {
Text("Hello World")
}
}
}
Fragment in Compose-based UI —
AndroidViewBinding
Fragment code
class BlankFragment : Fragment() {
var uri: Uri? = null
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
return ComposeView(requireContext()).apply {
// Dispose of the Composition when the view's LifecycleOwner is destroyed
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
setContent {
MaterialTheme {
// In Compose world
HomeScreen()
}
}
}
}
}
- Layout file —
FragmentContainerView
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/fragment_container_view"
android:name="com.example.compose.BlankFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
- Composable
AndroidViewBinding code
@Composable
fun FragmentUsingViewBindingInCompose(modifier: Modifier = Modifier) {
AndroidViewBinding(FragmentContainerBinding::inflate, modifier){
val blankFragment = fragmentContainerView.getFragment<BlankFragment>()
blankFragment.uri = Uri.parse("https://developer.android.com")
}
}
Job Offers
Fragment
in compose-based UI — AndroidFragment
AndroidFragment has been available since version 1.8.0 via
fragment-compose artifact
Composable code
@Composable
fun FragmentUsingAndroidFragmentInCompose(modifier: Modifier = Modifier) {
AndroidFragment<BlankFragment> { blankFragment ->
blankFragment.uri = Uri.parse("https://developer.android.com")
}
}
Navigation Fragment Composable
Starting with version 2.8.0 we get support for adding composable directly into
XML-based nav-graphs via
navigation-fragment-compose
2 important steps that must be implemented to use this API
- Each
composable
destination must be a top-level, no argument@Composable method
- A fully qualified name is used as the
android:name
attribute for each destination
💡Tip: for the file name you can use @file:JvmName annotation for better/custom naming — By default, Kotlin uses the
file name and appends
Kt
com.example.compose.HomeScreenKt$HomeScreen
@file:JvmName("HelloScreenComposableDestination")
package com.example.compose
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import com.example.compose.theme.YourTheme
@Composable
fun HomeScreen() {
Text("Hello")
}
@Preview
@Composable
private fun PreviewHomeComposable() {
YourTheme {
HomeScreen()
}
}
Nav graph with
composableas
destination
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/nav_graph"
app:startDestination="@+id/nav_fragmentWithContentExt">
<fragment
android:id="@+id/nav_fragmentWithContentExt"
android:name="com.example.compose.FragmentWithContentExt"
android:label="FragmentWithContentExt" />
<composable
android:id="@+id/nav_homeComposable"
android:name="com.example.compose.HomeScreenKt$HomeScreen"
/>
</navigation>
- Navigating to the
destination using its
ID
findNavController().navigate(R.id.nav_homeComposable)
Stay in touch
https://github.com/navczydev?source=post_page—–a9a8efee0040——————————–
https://x.com/navczydev?source=post_page—–a9a8efee0040——————————–
This article is previously published on proandroiddev.com