У меня есть действие, в котором находятся оба фрагмента: SourceFragment
и DestinationFragment
. SourceFragment
содержит RecyclerView
, а DestinationFragment
содержит ViewPager
. Я использовал менеджер фрагментов, чтобы переключаться между фрагментом «Источник» и «Место назначения».
Проблема:
Обратный переход работает нормально до тех пор, пока я не проведу по другомуПосмотреть на ViewPager. Чтобы решить эту проблему, я переопределил onMapSharedElements
в DestinationFragment
и SourceFragment
, чтобы убедиться, что представления совпадают друг с другом, когда выполняется просмотр страницы. По какой-то причине смахивание и возврат к SourceFragment не работают и анимация перехода не происходит. Я даже отладил функции onMapSharedElements
, чтобы убедиться, что представления отображаются правильно.
Это то, что я пытаюсь реализовать.
Моя реализация
Я предоставил приведенный ниже код для рассматриваемых фрагментов, но вот репо для моей реализации. Я целую неделю мучился, пытаясь понять это, надеюсь, я смогу понять, почему это происходит.
SourceFragment:
class SourceFragment : Fragment() {
private lateinit var sharedViewModel: SharedViewModel
private lateinit var itemRecyclerView: RecyclerView
private lateinit var adapter: SourceAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setExitSharedElementCallback(object : SharedElementCallback() {
override fun onMapSharedElements(names: MutableList<String>?, sharedElements: MutableMap<String, View>?) {
val view = itemRecyclerView.findViewHolderForAdapterPosition(sharedViewModel.currentPos)
?.itemView?.findViewById<TextView>(R.id.source_text)
val item = sharedViewModel.itemList[sharedViewModel.currentPos]
if (view == null) return
names?.clear()
sharedElements?.clear()
names?.add(item)
sharedElements?.put(item, view)
}
})
sharedViewModel = ViewModelProviders.of(requireActivity()).get(SharedViewModel::class.java)
adapter = SourceAdapter(object : onClickItem {
override fun onClick(position: Int, view: View) {
// Save the position of the item that was clicked.
sharedViewModel.currentPos = position
// Setup shared element transition
val transitionName = ViewCompat.getTransitionName(view) ?: ""
// Start fragment transaction along with shared element transition.
fragmentManager?.apply {
beginTransaction()
.setReorderingAllowed(true)
.addSharedElement(view, transitionName)
.replace(
R.id.fragment_container,
DestinationFragment(),
DestinationFragment::class.java.simpleName
)
.addToBackStack(null)
.commit()
}
}
})
val list = sharedViewModel.itemList
adapter.submitList(list)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view = inflater.inflate(R.layout.source_layout, container, false)
postponeEnterTransition()
return view
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// Setup recycler view here
itemRecyclerView = item_recycler_view
itemRecyclerView.layoutManager = GridLayoutManager(requireContext(), 2)
itemRecyclerView.adapter = adapter
// Start enter transition on pre draw.
itemRecyclerView.viewTreeObserver.addOnPreDrawListener(object : ViewTreeObserver.OnPreDrawListener {
override fun onPreDraw(): Boolean {
itemRecyclerView.viewTreeObserver.removeOnPreDrawListener(this)
startPostponedEnterTransition()
return true
}
})
// Scroll to the position of the item that was selected in the Destination Fragment.
itemRecyclerView.addOnLayoutChangeListener { p0, p1, p2, p3, p4, p5, p6, p7, p8 ->
val layoutMan = itemRecyclerView.layoutManager
val viewAtPos = layoutMan?.findViewByPosition(sharedViewModel.currentPos)
if (viewAtPos == null ||
layoutMan.isViewPartiallyVisible(viewAtPos, false, true)
) {
itemRecyclerView.post {
layoutMan?.scrollToPosition(sharedViewModel.currentPos)
}
}
}
}
DestinationFragment
class DestinationFragment : Fragment(), MainActivityListener {
lateinit var sharedViewModel: SharedViewModel
lateinit var destPager : ViewPager
lateinit var itemAdapter : ItemPagerAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
postponeEnterTransition()
setEnterSharedElementCallback(object : androidx.core.app.SharedElementCallback(){
override fun onMapSharedElements(names: MutableList<String>?, sharedElements: MutableMap<String, View>?) {
val item = sharedViewModel.itemList[destPager.currentItem]
val itemView = (itemAdapter.instantiateItem(destPager, destPager.currentItem) as Fragment).view?.findViewById<TextView>(R.id.item_fragment_textview) as View
names?.clear()
names?.add(item)
sharedElements?.clear()
sharedElements?.put(item, itemView)
}
})
sharedElementEnterTransition = TransitionInflater.from(requireContext()).inflateTransition(android.R.transition.move)
sharedViewModel = ViewModelProviders.of(requireActivity()).get( SharedViewModel::class.java)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.destination_layout, container ,false)
}
override fun onBackPressed(): Boolean {
sharedViewModel.currentPos = destPager.currentItem
return false
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
destPager = destination_pager
itemAdapter = ItemPagerAdapter(sharedViewModel.itemList, childFragmentManager)
destination_pager.adapter = itemAdapter
destination_pager.currentItem = sharedViewModel.currentPos
}