Search code examples
androidandroid-fragmentsandroid-viewpager2

Accessing Parent's Fragment function from Viewpager2 fragment


I am using Navigation Component and inside my home fragment there is a ViewPager2. We knew that viewPager2 contains of Fragment too. How to call parent's function through fragment of viewpager2? I have tried some method like passing function in constructor but i realized the fragment created with singleton mode. I only know how to pass functions in constructor like standart class (Not Singleton class)

My Adapter

class DetailSliderAdapter(fragmentActivity: FragmentActivity) : FragmentStateAdapter(fragmentActivity) {

    private val images = mutableListOf<String>()

    fun addImages(lsImage: List<String>){
        images.addAll(lsImage)
        notifyDataSetChanged()
    }

    override fun getItemCount(): Int = images.size
    override fun createFragment(position: Int): Fragment {
        return SliderImageFragment.newInstance(images[position])
    }

    class SliderImageFragment: Fragment(){
        companion object{
            const val EXTRA_SLIDER_IMAGE = "extra_slider_image"
            fun newInstance(imageStr: String) = SliderImageFragment().apply {
                this.arguments = Bundle().apply {
                    this.putString(EXTRA_SLIDER_IMAGE, imageStr)
                }
            }

        }

        override fun onCreateView(
            inflater: LayoutInflater,
            container: ViewGroup?,
            savedInstanceState: Bundle?
        ): View? {
            return inflater.inflate(R.layout.item_slide_image, container, false)
        }

        override fun onActivityCreated(savedInstanceState: Bundle?) {
            super.onActivityCreated(savedInstanceState)

            val image = arguments?.getString(EXTRA_SLIDER_IMAGE) as? String

            image?.let {
                Picasso.get()
                    .load(image)
                    .into(image_slide)

                image_slide.setOnClickListener {
                    
                    // here i want to call parent's Fragment  function
              
            }
        }
    }
}

My Fragment home

class DetailFragment : Fragment() {
    private var root: View ?= null
    private var viewpagerSlider : ViewPager2 ?= null

    private val viewModel : DetailViewModel by lazy {
        ViewModelProviders.of(this, factory).get(DetailViewModel::class.java)
    }

    private val adapterSlider : DetailSliderAdapter by lazy {
        DetailSliderAdapter(requireActivity()){
            //listener
        }
    }

    fun clearAllAdapter(){
        // NEED TO CALL THIS
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        val safeArgs : DetailFragmentArgs by navArgs<DetailFragmentArgs>()
        idProduct = safeArgs.idProduct
        Timber.d("ID PRODUCT $idProduct")

        if(root == null){
            root = inflater.inflate(R.layout.fragment_detail, container, false)
            idProduct?.let {
                viewModel.getDetail(idProduct!!)
            }
        }
        return root
    }


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

        Timber.d("CALL onViewCreated")

        viewModel.getDataDetail().observe(viewLifecycleOwner, Observer {
            when(it.status){
                
                Response.ResponseStatus.LOADED -> {
                    progress_circular.visibility = View.GONE
                    val data = it.data
                    data?.let { d->
                        val detailProduct = d.detailProduct
                        detailProduct?.let { pd->
                            updateUI(pd, data)
                        }

                    }
                }
               
            }

        })
    }

    private fun updateUI(pd: ProductDetail, data: Data) {
        pd.image?.let {
            updateSliderPhoto(pd.image)
        }
    }

    private fun updateSliderPhoto(
        image: List<String>
    ) {
        viewpagerSlider = root?.findViewById(R.id.slider_photo)
        adapterSlider.addImages(image)

        viewpagerSlider?.apply {
            this.adapter = adapterSlider
            this.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback(){
                override fun onPageSelected(position: Int) {
                    super.onPageSelected(position)
                    page_indicator.text = "${(position+1)}/${image.size}"
                }
            })
        }
    }

}

Solution

  • You should never be passing the FragmentActivity to your FragmentStateAdapter when in a Fragment - that's why there's a FragmentStateAdapter constructor that takes a Fragment. It is only that Fragment constructor that properly nests the ViewPager2 fragments in your parent fragment.

    Once using the right constructor, your SliderImageFragment can call requireParentFragment() and cast it to DetailFragment and call your method.