【问题标题】:Kotlin OnItemClickListener for a RecyclerView inside a Fragment片段内的 RecyclerView 的 Kotlin OnItemClickListener
【发布时间】: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)”片段,但每次我尝试实施解决方案时,应用程序在单击项目时崩溃回收站视图。现在导航可以通过单击工具栏菜单中的按钮来工作,但这不是理想的解决方案。

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

【问题讨论】:

    标签: kotlin android-fragments android-recyclerview onitemclicklistener


    【解决方案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() }
    }
    

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

    1. 将导航器实例提供给适配器
    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()
    }
    
    1. 制作回调接口

    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 提供单击侦听器,但是在此示例中,视图只能在适配器内部访问。要么我们将视图从适配器传递到片段,要么适配器将通过回调通知片段。您如何在没有参考的情况下从适配器进行回调?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-03-07
    • 2022-07-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多