Home > Back-end >  Compose not show when replace fragment container
Compose not show when replace fragment container

Time:01-30

I've worked on the FragmentContainerView activity with some fragments, in that fragment, I want to use Compose alongside XML using ComposeViewin the first fragment, but when I try to navigate from the second fragment and back to the first fragment, the component from ComposeView was disappeared.

I've set up a fragment with FragmentContainerView using the replace strategy and I put the fragment inside the list like usual, and I have no idea what happens with this situation.

You can watch in this video

also this is my code

NavigationActivity.kt

import android.os.Bundle
import android.view.MenuItem
import androidx.appcompat.app.AppCompatActivity
import androidx.core.net.toUri
import androidx.navigation.NavDeepLinkRequest
import androidx.navigation.Navigation
import androidx.navigation.findNavController
import id.derysudrajat.inlinebinding.viewBinding
import id.derysudrajat.library.R
import id.derysudrajat.library.databinding.ActivityNavigationBinding

class NavigationActivity : AppCompatActivity() {

    private val binding by viewBinding(ActivityNavigationBinding::inflate)

    private val listOfFragment = listOf(FragmentMainNav(), FragmentDetailNav())

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(binding.root)

        binding.btnHome.setOnClickListener{
            replace(HOME_NAV)
        }
        binding.btnDetail.setOnClickListener{
            replace(DETAIL_NAV)
        }
        Navigation.createNavigateOnClickListener(R.id.fragmentDetailNav, null)
    }

    private fun replace(nav: String) {
        supportFragmentManager
            .beginTransaction()
            .replace(
                binding.fragmentContainerView.id,
                if (nav == HOME_NAV) listOfFragment[0] else listOfFragment[1]
            )
            .commit()
    }

    companion object {
        const val HOME_NAV = "home_nav"
        const val DETAIL_NAV = "detail_nav"
    }
}

FragmentMainNav.kt

import android.os.Bundle
import android.view.View
import androidx.compose.material3.Text
import androidx.compose.ui.platform.ViewCompositionStrategy
import androidx.lifecycle.Lifecycle
import androidx.navigation.findNavController
import id.derysudrajat.inlinebinding.BindingFragment
import id.derysudrajat.inlinebinding.viewBinding
import id.derysudrajat.library.R
import id.derysudrajat.library.databinding.FragmentNavMainBinding

class FragmentMainNav : BindingFragment<FragmentNavMainBinding>() {

    override val binding by viewBinding(FragmentNavMainBinding::inflate)

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        binding.textMain.text = "Fragment Main"

        binding.composeView.apply {
            setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
            setContent { 
                Text(text = "This is Compose")
            }
        }

    }
}

fragment_nav_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@ id/text_main"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Fragment Main"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <androidx.compose.ui.platform.ComposeView
        android:id="@ id/compose_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@ id/text_main" />

</androidx.constraintlayout.widget.ConstraintLayout>

FragmentDetailNav.kt

import android.os.Bundle
import android.view.View
import id.derysudrajat.inlinebinding.BindingFragment
import id.derysudrajat.inlinebinding.viewBinding
import id.derysudrajat.library.databinding.FragmentNavDetailBinding
import id.derysudrajat.library.databinding.FragmentNavMainBinding

class FragmentDetailNav : BindingFragment<FragmentNavDetailBinding>() {

    override val binding by viewBinding(FragmentNavDetailBinding::inflate)

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        binding.textDetail.text = "Detail Navigation"
    }
}

fragment_nav_detail.kt

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@ id/text_detail"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Detail Navigation"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

I've tried to using different way like changing ViewCompositionStrategy and it stil not working, I expected to show ComopseView still show when fragment was replaced and back, btw the compose that I was tried is from compose BOM 2022.10.00 - 2023.01.00 but still dissapeared when fragment was replaced.

CodePudding user response:

I think you could move the binding.composeView.apply {} block from onViewCreated to onCreateView as shown by provided sample in official documentation here. I've tested it using compose bom 2023.01.00 and plain ViewBinding and it works fine. So the HomeFragment would be like this:

class HomeFragment : Fragment() {

    private var _binding: FragmentHomeBinding? = null
    private val binding get() = _binding!!

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        _binding = FragmentHomeBinding.inflate(inflater, container, false)
        val view = binding.root
        binding.composeView.apply {
            setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
            setContent {
                Text(text = "This is Compose")
            }
        }
        return view
    }

    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null
    }
}

As additional note, i don't think the Navigation.createNavigateOnClickListener() is necessary and could just be removed.

  • Related