片段内的 RecyclerView 的 Kotlin OnItemClickListener

Posted

技术标签:

【中文标题】片段内的 RecyclerView 的 Kotlin OnItemClickListener【英文标题】:Kotlin OnItemClickListener for a RecyclerView inside a Fragment 【发布时间】:2021-06-29 03:59:45 【问题描述】:

问题与我无法通过在适配器中实现 OnClickListener 来为位于“mainFragment”中的 RecyclerView 实现 OnItemClick 侦听器有关。

我希望我的应用程序 (kotlin) 每次单击 RecyclerView 中的 itemView(一个 ImageView)时启动另一个片段(以下代码中的“deletePage”),这个片段将显示同一张照片。

我的适配器代码如下:

 class MyAdapter : RecyclerView.Adapter<MyAdapter.MyViewHolder>() 

    private var photo = emptyList<Photo>()
    
    inner class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder 
        return MyViewHolder(
            LayoutInflater.from(parent.context).inflate(R.layout.row_layout, parent, false)
        )
    

    override fun getItemCount(): Int 
        return photo.size
    

    override fun onBindViewHolder(holder: MyViewHolder, position: Int) 
        holder.itemView.longitude.text = photo[position].latitude
        holder.itemView.latitude.text = photo[position].longitude
        holder.itemView.imageView.load(photo[position].photo)
    

    fun setData(photo: List<Photo>) 
        this.photo = photo
        notifyDataSetChanged()
    

而我的 mainFragment 代码如下:

class MainFragment : Fragment()

    private lateinit var myView: MyViewModel
    private val adapter by lazy  MyAdapter() 

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? 
        // Inflate the layout for this fragment
        val view = inflater.inflate(R.layout.fragment_main, container, false)

        //Recyclerview
        val adapter = MyAdapter()
        val recyclerView = view.recycler_view
        recyclerView.adapter = adapter
        recyclerView.layoutManager = LinearLayoutManager(requireContext())

        myView = ViewModelProvider(this).get(MyViewModel::class.java)
        myView.readPhoto.observe(viewLifecycleOwner, Observer photo ->
            adapter.setData(photo)
        )

        setHasOptionsMenu(true)

        return view
    

    override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) 
        inflater.inflate(R.menu.menu_database, menu)
    

    override fun onOptionsItemSelected(item: MenuItem): Boolean 
        when 
            item.itemId == R.id.deleteAll -> findNavController().navigate(R.id.deletePage)
            item.itemId == R.id.refresh -> 
                Toast.makeText(activity, "yep", Toast.LENGTH_SHORT).show()
                instertDataToDatabase()
            
        
        if (item.itemId == R.id.deleteAll) 
        
        return super.onOptionsItemSelected(item)
    

目标是,当您单击 RecyclerView 的项目时,会显示“findNavController().navigate(R.id.deletePage)”片段,但每次我尝试实施解决方案时,应用程序在单击项目时崩溃回收站视图。现在导航可以通过单击工具栏菜单中的按钮来工作,但这不是理想的解决方案。

非常感谢任何形式的帮助或建议!

【问题讨论】:

【参考方案1】:

首先,您需要在onBindViewHolder 中为您的 itemView 提供点击监听器

override fun onBindViewHolder(holder: MyViewHolder, position: Int) 
    holder.itemView.longitude.text = photo[position].latitude
    holder.itemView.latitude.text = photo[position].longitude
    holder.itemView.imageView.load(photo[position].photo)
    holder.itemView.setOnClickListener  navigateToFragment() 

对于导航,您应该有一个上下文实例。 以下是我想到的可能的解决方案:

    将导航器实例提供给适配器
class Navigator(fragment: Fragment) 
    private val fragmentRef = WeakReference(fragment)

    fun navigate()
        // make your navigations here with using fragmentRef.get()
    

在您的片段中:

private val navigator = Navigator(this)
         ...
val adapter = MyAdapter(navigator)

在您的适配器中:

class MyAdapter(private val navigator: Navigator) : RecyclerView.Adapter<MyAdapter.MyViewHolder>() 

fun navigateToFragment()
   navigator.navigate()

    制作回调接口

2.1。在片段中实现该接口并为适配器提供接口实例

interface Navigable
   fun navigate()

在您的片段中:

class MainFragment : Fragment(), Navigable
      ...

override fun navigate()
    // make your navigation


val adapter = MyAdapter(navigator)

在您的适配器中:

class MyAdapter(private val navigable: Navigable) : RecyclerView.Adapter<MyAdapter.MyViewHolder>() 

fun navigateToFragment()
   navigable.navigate()

2.2。制作接口,但不传引用,在adapter中使用findFragment

在您的适配器中:覆盖 onAttachedToRecyclerView 以查找片段

private lateinit var navigable: Navigable

override fun onAttachedToRecyclerView(recyclerView: RecyclerView) 
    super.onAttachedToRecyclerView(recyclerView)
    navigable = recyclerView.findFragment<Fragment>() as Navigable


fun navigateToFragment()
   navigable.navigate()

【讨论】:

我不认为适配器应该实现点击逻辑或保留对主机片段的引用。相反,我认为公开一个回调并使用它来实现片段的操作会是一个更好的解决方案。 我更喜欢使用数据绑定并从 xml 提供单击侦听器,但是在此示例中,视图只能在适配器内部访问。要么我们将视图从适配器传递到片段,要么适配器将通过回调通知片段。您如何在没有参考的情况下从适配器进行回调?

以上是关于片段内的 RecyclerView 的 Kotlin OnItemClickListener的主要内容,如果未能解决你的问题,请参考以下文章

E/RecyclerView:没有附加适配器;在片段内的recyclerview上跳过布局

在通知单击时将项目添加到片段内的 recyclerview

android studio中片段内的RecyclerView使我的应用程序崩溃

android RecyclerView pinch zoom,ScaleGestureDetector&GridLayoutManager,with BigImageViewer,kotli

片段中 RecyclerView 的 NullPointerException

RecyclerView 内容未使用片段父级的全宽