共享的元素不会返回到RecyclerView项目

问题描述

我有一个名为MainFragment的片段,其中包含一个ViewPager,该ViewPager包含另一个名为LibraryFragment的片段。

LibraryFragment包含一个RecyclerView以及一个包含ImageView的项目列表。 ImageView的内容随Coil一起加载。

单击某个项目时,LibraryFragment导航到另一个名为ArtistDetailFragment的片段,并使用该项目中的ImageView。

问题在于,尽管回车过渡效果很好,但是ImageView在向后导航时不会返回到列表项,只会消失。香港专业教育学院附上以下示例:

enter image description here

我已经尝试过使用postponeEnterTransition()startPostponedEnterTransition()以及添加SharedElementCallback方法,但都效果不佳。我还排除了线圈问题。

这里LibraryFragment

class LibraryFragment : Fragment() {

    private val musicModel: Musicviewmodel by activityviewmodels()
    private val libraryModel: Libraryviewmodel by activityviewmodels()

    private lateinit var binding: FragmentLibraryBinding

    override fun onCreateView(
        inflater: LayoutInflater,container: ViewGroup?,savedInstanceState: Bundle?
    ): View? {
        binding = FragmentLibraryBinding.inflate(inflater)

        binding.libraryRecycler.adapter = ArtistAdapter(
            musicModel.artists.value!!,BindingClickListener { artist,itembinding ->
                navToArtist(artist,itembinding)
            }
        )

        return binding.root
    }

    private fun navToArtist(artist: Artist,itembinding: ItemArtistBinding) {
        // When navigation,pass the artistimage of the item as a shared element to create
        // the image popup.
        findNavController().navigate(
            MainFragmentDirections.actionShowArtist(artist.id),FragmentNavigatorExtras(
                itembinding.artistimage to itembinding.artistimage.transitionName
            )
        )
    }
}

这里ArtistDetailFragment

class ArtistDetailFragment : Fragment() {

    override fun onCreateView(
        inflater: LayoutInflater,savedInstanceState: Bundle?
    ): View? {
        val binding = FragmentArtistDetailBinding.inflate(inflater)
    
        sharedElementEnterTransition = TransitionInflater.from(requireContext())
            .inflateTransition(android.R.transition.move)
    
        val musicModel: Musicviewmodel by activityviewmodels()
        val artistId = ArtistDetailFragmentArgs.fromBundle(requireArguments()).artistId
    
        // Get the transition name used by the recyclerview ite
        binding.artistimage.transitionName = artistId.toString()
    
        binding.artist = musicModel.artists.value?.find { it.id == artistId }
    
        return binding.root
    }
}

还有RecyclerView适配器/ ViewHolder:

class ArtistAdapter(
    private val data: List<Artist>,private val listener: BindingClickListener<Artist,ItemArtistBinding>
) : RecyclerView.Adapter<ArtistAdapter.ViewHolder>() {

    override fun getItemCount(): Int = data.size

    override fun onCreateViewHolder(parent: ViewGroup,viewType: Int): ViewHolder {
        return ViewHolder(
            ItemArtistBinding.inflate(LayoutInflater.from(parent.context))
        )
    }

    override fun onBindViewHolder(holder: ViewHolder,position: Int) {
        holder.bind(data[position])
    }

    // Generic ViewHolder for an artist
    inner class ViewHolder(
        private val binding: ItemArtistBinding
    ) : RecyclerView.ViewHolder(binding.root) {

        // Bind the view w/new data
        fun bind(artist: Artist) {
            binding.artist = artist

            binding.root.setonClickListener { listener.onClick(artist,binding) }

            // Update the transition name with the new artist's ID.
            binding.artistimage.transitionName = artist.id.toString()

            binding.executePendingBindings()
        }
    }
}

编辑:我这样使用postponeEnterTransitionstartPostponedEnterTransition

// LibraryFragment
override fun onResume() {
    super.onResume()

    postponeEnterTransition()

    // Refresh the parent adapter to make the image reappear
    binding.libraryRecycler.adapter = artistAdapter

    // Do the Pre-Draw listener
    binding.libraryRecycler.viewTreeObserver.addOnPreDrawListener {
        startPostponedEnterTransition()
        true
    }
}

这只会使RecyclerView本身刷新,但是,共享元素仍然消失而不是返回到RecyclerView项目。

Problem Again

解决方法

克里斯贝恩斯说;

您可能想知道为什么我们在父级而不是视图本身上设置 OnPreDrawListener。那是因为您的视图可能实际上没有被绘制,因此侦听器永远不会触发并且事务将永远推迟在那里。为了解决这个问题,我们在父级上设置了侦听器,它(可能)会被绘制。

https://chris.banes.dev/fragmented-transitions/

试试这个;

改变

// LibraryFragment
override fun onResume() {
    super.onResume()

    postponeEnterTransition()

    // Refresh the parent adapter to make the image reappear
    binding.libraryRecycler.adapter = artistAdapter

    // Do the Pre-Draw listener
    binding.libraryRecycler.viewTreeObserver.addOnPreDrawListener {
        startPostponedEnterTransition()
        true
    }
}
enter code here

   override fun onCreateView(
        inflater: LayoutInflater,container: ViewGroup?,savedInstanceState: Bundle?
    ): View? {
        postponeEnterTransition()
        binding = FragmentLibraryBinding.inflate(inflater)

        binding.libraryRecycler.adapter = ArtistAdapter(
            musicModel.artists.value!!,BindingClickListener { artist,itemBinding ->
                navToArtist(artist,itemBinding)
            }
        )

    (view?.parent as? ViewGroup)?.doOnPreDraw {
      // Parent has been drawn. Start transitioning!
      startPostponedEnterTransition()
    }

        return binding.root
    }