0

I am struggling with returning transition while using MaterialMotion. Here is the logic I am trying to implement -

I have FirstFragment with ViewPager where one of the pages (StartTransitionFragment) contains a recycler with items. When item in the recycler is clicked the transition is started.

The transition goes to DetailsFragment which holds in it's turn another ViewPager with detailed fragments (EndTransitionFragmnet).

As for the reverse path - when EndTransitionFragmnet gets closed the reverse transition is happening and I want to have a possibility to remap the shared elements when I return to StartTransitionFragment.

Everything works well until I have introduced the ViewPager to FirstFragment - I got setExitSharedElementCallback fired on StartTransitionFragment and able to do manipulations with elements. However when StartTransitionFragment is one of the fragments in FirstFragment's ViewPager I have to set exitSharedElementCallback to FirstFragment (and call postponeEnterTransition() / startPostponedEnterTransition() on the FirstFragment as well).

Is there a way I can get return transition callbacks fired on StartTransitionFragment rather than on FirstFragment in that configuration?

Fragment with ViewPager -

class FirstFragment : Fragment() {

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

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        _binding = FragmentFirstBinding.inflate(inflater, container, false)
        return binding.root
    }

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

        postponeEnterTransition()
        view.doOnPreDraw {
            startPostponedEnterTransition()
        }

        setExitSharedElementCallback(object : SharedElementCallback() {
            override fun onMapSharedElements(names: List<String?>?, sharedElements: Map<String?, View?>) {
                super.onMapSharedElements(names, sharedElements)
                println(">>>> FIRST EXIT ${names.toString()} $sharedElements")
                // fired when transition starts to target
                // fired when transition returns from target
            }
        })

        binding.vpMain.adapter = MainPagerAdapter(requireActivity().supportFragmentManager, lifecycle)
    }
}

class MainPagerAdapter (
    fragmentManager: FragmentManager,
    lifecycle: Lifecycle,
) : FragmentStateAdapter(fragmentManager, lifecycle) {

    private val fragments: List<Fragment> = arrayListOf(
        StartTransitionFragment(),
        OtherFragment()
    )

    override fun getItemCount() = fragments.size
    override fun createFragment(position: Int) = fragments[position]
}

Fragment where transition starts -

class StartTransitionFragment : Fragment(), StoryScrollAdapter.StoryScrollListener {

    private lateinit var storyAdapter: StoryScrollAdapter

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

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        _binding = FragmentStartTransitionBinding.inflate(inflater, container, false)
        return binding.root
    }

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

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

    private fun setUpStoryScrollRecyclerView() {
        binding.rvItems.layoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false)
        storyAdapter = StoryScrollAdapter(this)
        binding.rvItems.adapter = storyAdapter

        val items = listOf(0, 1, 2)
        storyAdapter.setItems(items)
    }

    override fun onClickedStoryScroll(model: Int, view: View) {
        val extras = FragmentNavigatorExtras(view to "transition_id_$model")

        setExitSharedElementCallback(object : SharedElementCallback() {
            override fun onMapSharedElements(names: List<String?>?, sharedElements: Map<String?, View?>) {
                super.onMapSharedElements(names, sharedElements)
                println(">>>> START EXIT TRANSITION ${names.toString()} $sharedElements")
                // this is NOT fired!!!
            }
        })

        val bundle = bundleOf("PAGE_TO_OPEN" to model)
        findNavController().navigate(R.id.detailsFragment, bundle, null, extras)
    }
}

Fragment with ViewPager showing details (here transition ends) -

class DetailsFragment : Fragment() {

    private lateinit var adapter: DetailsPagerAdapter

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

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        _binding = FragmentDetailsBinding.inflate(inflater, container, false)
        return binding.root
    }

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

    private fun initViewPager() {

        adapter = DetailsPagerAdapter(requireActivity().supportFragmentManager, lifecycle)
        binding.vpDetails.adapter = adapter

        binding.vpDetails.doOnAttach {
            binding.vpDetails.setCurrentItem(requireArguments().getInt("PAGE_TO_OPEN"), false)
            binding.vpDetails.transitionName = "transition_id_" + requireArguments().getInt("PAGE_TO_OPEN")

            sharedElementEnterTransition = MaterialContainerTransform().apply {
                drawingViewId = R.id.nav_host_fragment_content_main
                scrimColor = Color.TRANSPARENT
            }

            setEnterSharedElementCallback(object : SharedElementCallback() {
                override fun onMapSharedElements(names: List<String?>?, sharedElements: Map<String?, View?>) {
                    super.onMapSharedElements(names, sharedElements)
                    println(">>>> DETAILS ENTER ${names.toString()} $sharedElements")
                }
            })
        }

        binding.vpDetails.offscreenPageLimit = adapter.itemCount
    }
}

class DetailsPagerAdapter (
    fragmentManager: FragmentManager,
    lifecycle: Lifecycle,
) : FragmentStateAdapter(fragmentManager, lifecycle) {

    private val fragments: List<Fragment> = arrayListOf(
            EndTransitionFragment("Details fragment #1"),
            EndTransitionFragment("Details fragment #2"),
            EndTransitionFragment("Details fragment #3"),
        )

    override fun getItemCount() = fragments.size
    override fun createFragment(position: Int) = fragments[position]
}
Arkados
  • 1
  • 1

0 Answers0