Thaw De Zin
Thaw De Zin

Reputation: 1669

Fragment Container in Jetpack Compose

I want to develop a single Activity multi fragments Apps using Jetpack Compose. For recyclerView, we have Vertical and HorizontalScroller. But, for fragments what should I use.

fun loadFragment(fragment: Fragment) {
            val transaction:FragmentTransaction = supportFragmentManager.beginTransaction()
            transaction.replace(R.id.f_container, fragment)
            transaction.addToBackStack(null)
            transaction.commit()
        }

In this case, I don't have R.id.f_container because I'm creating UI using only compose.

<FrameLayout
    android:id="@+id/f_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"`enter code here`
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    app:layout_constraintEnd_toEndOf="parent"
    tools:layout_editor_absoluteY="-56dp">
</FrameLayout>

Upvotes: 22

Views: 17372

Answers (4)

Abdul Aleem
Abdul Aleem

Reputation: 709

Probably late for the answer, just leaving it so others find it useful.

Since version 1.8.1, the Android development framework includes an AndroidFragment composable, which facilitates the integration of Fragments into Compose.

For more information, visit the AndroidFragment Release Notes.

Here is an example of how to use AndroidFragment:

@Composable
fun ExampleInteropScreen() {
   AndroidFragment<ExampleFragment>(
        modifier = Modifier
            .fillMaxSize()
   )
}

This composable allows developers to seamlessly use Fragments within a Compose UI, enhancing interoperability and expanding the capabilities of modern Android applications.

Upvotes: 3

Yevhen Railian
Yevhen Railian

Reputation: 611

You can create your own @Composable FragmentContainer function

@Composable
fun FragmentContainer(
    modifier: Modifier = Modifier,
    fragmentManager: FragmentManager,
    commit: FragmentTransaction.(containerId: Int) -> Unit
) {
    val containerId by rememberSaveable { mutableStateOf(View.generateViewId()) }
    var initialized by rememberSaveable { mutableStateOf(false) }
    AndroidView(
        modifier = modifier,
        factory = { context ->
            FragmentContainerView(context)
                .apply { id = containerId }
        },
        update = { view ->
            if (!initialized) {
                fragmentManager.commit { commit(view.id) }
                initialized = true
            } else {
                fragmentManager.onContainerAvailable(view)
            }
        }
    )
}

/** Access to package-private method in FragmentManager through reflection */
private fun FragmentManager.onContainerAvailable(view: FragmentContainerView) {
    val method = FragmentManager::class.java.getDeclaredMethod(
        "onContainerAvailable",
        FragmentContainerView::class.java
    )
    method.isAccessible = true
    method.invoke(this, view)
}

and then use it in activity

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContent {
        FragmentContainer(
            modifier = Modifier.fillMaxSize(),
            fragmentManager = supportFragmentManager,
            commit = { add(it, YourFragment()) }
        )
    }
}

or in fragment

override fun onCreateView(
    inflater: LayoutInflater,
    container: ViewGroup?,
    savedInstanceState: Bundle?
): View = ComposeView(requireContext()).apply {
    setContent {
        FragmentContainer(
            modifier = Modifier.fillMaxSize(),
            fragmentManager = parentFragmentManager,
            commit = { add(it, YourNestedFragment()) }
        )
    }
}

Upvotes: 13

Daniele
Daniele

Reputation: 1160

I would not suggest you reuse an existing fragment, but instead, try to recycle its inner views to create a new composable.

Anyway if you want to have fun here is a possible solution:

AndroidView(
modifier = Modifier
    .fillMaxHeight()
    .fillMaxWidth(),
factory = { context ->
    FrameLayout(context).apply {
        FragmentBlankBinding.inflate(LayoutInflater.from(context), this, true).root
    }
})

Enjoy!

Upvotes: 4

Vinay Gaba
Vinay Gaba

Reputation: 1214

If you are creating a new app, you can skip using Fragments altogether and just use composable functions to represent your screens.

Upvotes: -2

Related Questions