RecyclerView 适配器中的导航组件

Posted

技术标签:

【中文标题】RecyclerView 适配器中的导航组件【英文标题】:Navigation Component in RecyclerView Adapter 【发布时间】:2019-11-28 18:13:30 【问题描述】:

我在适配器中编写了以下代码。

holder.itemView.setOnClickListener 
    val action = SearchFragmentDirections.actionSearchFragmentToArtistFragment(artist.id)
    Navigation.createNavigateOnClickListener(action)

这是可能的导航xml:

 ...
    <fragment android:id="@+id/searchFragment"
          android:name="com.salmanseifian.spotiny.ui.search.SearchFragment"
          android:label="SearchFragment">

    <action android:id="@+id/action_searchFragment_to_artistFragment"
            app:destination="@id/artistFragment"
            app:popUpTo="@+id/searchFragment"/>
</fragment>

但它不会工作。有人可以帮忙吗?

【问题讨论】:

你确定holder.itemView.setOnClickListenerSearchFragment里面吗? @JohnJoe 是的,我确定。 【参考方案1】:

您正在使用 lambda,它本身就是一个点击监听器。 检查这个Navigation Docs,它使用导航ID和createNavigationListener正确实现了点击监听器。

为您的案例使用以下代码。

holder.itemView.setOnClickListener(
Navigation.createNavigateOnClickListener(R.id.action_searchFragment_to_artistFragment)
)

或者,试试这个方法

holder.itemView.setOnClickListener view ->
 view.findNavController().navigate(R.id.action_searchFragment_to_artistFragment)

【讨论】:

不幸的是,它没有帮助。问题依然存在。 holder.itemView.setOnClickListener( Navigation.createNavigateOnClickListener(R.id.productDetailsFragment) );是的,这对我有用,谢谢【参考方案2】:

我认为最好将此添加到已接受的答案中:

holder.itemView.setOnClickListener(
 Navigation
 .createNavigateOnClickListener(R.id.action_searchFragment_to_artistFragment).onClick(holder.itemView)
)

【讨论】:

我得到:does not have a NavController set【参考方案3】:

在您的 RecyclerView Adapter OnBindViewHolder 方法中,您可以这样:

        holder.bookBtn.setOnClickListener(view -> 
            Bundle bundle = new Bundle();
            String salonJsonString = 
            HelperMethods.getGsonParser().toJson(salonModel);bundle.putString("SALON_DETAILS", salonJsonString);
            Navigation.findNavController(view).navigate(R.id.salonDetailFragment,bundle);     
        );

在上面,目标是SalonDetailFragment,其id 是salonDetailFragment,并将数据作为Bundle 传递到目标。

我的导航配置

<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/mobile_navigation"
    android:label="Salon"
    app:startDestination="@+id/nav_home">
    <fragment
        android:id="@+id/nearbySalonsFragment"
        android:name="my.package.NearbySalonsFragment"
        android:label="Nearby Salons"
        tools:layout="@layout/fragment_nearby_salons" >
        <action
            android:id="@+id/action_nearbySalonsFragment_to_salonDetailFragment"
            app:destination="@id/salonDetailFragment" />
    </fragment>
    <fragment
        android:id="@+id/salonDetailFragment"
        android:name="my.package.SalonDetailFragment"
        android:label="Salon Details"
        tools:layout="@layout/fragment_salon_detail" />
</navigation>

【讨论】:

更多信息developer.android.com/guide/navigation/navigation-navigate 为我工作。谢谢。【参考方案4】:

如果你使用viewBinding,这是连击

view.btnCategory.setOnClickListener 
    val navController= Navigation.findNavController((view.root.context) as Activity, R.id.nav_host_home)
    navController.navigate(R.id.action_movieFragment2_to_settingsFragment2)

【讨论】:

为了更漂亮的答案,您可以将部分代码格式化为编辑答案。那么你的答案会更容易阅读。欢迎来到 *** :)【参考方案5】:

基本上,您可以通过两种方式做到这一点。

    您可以实例化 Navigation 类并创建导航点击监听器

      private fun openEditUser() 
         binding.userName.setOnClickListener 
    
          Navigation.createNavigateOnClickListener(R.id.addEditUserFragment)
             
         
    

    您可以从按钮或您在项目布局中使用的任何其他元素获取视图,并使用 navigate() 方法调用 findNavController

     private fun openEditUser() 
     binding.userName.setOnClickListener 
         it.findNavController().navigate(R.id.addEditUserFragment)
     
    

在这两种情况下,您都需要来自将用于导航的操作 ID 的引用,您可以在片段 XML 标记下的导航文件夹中查看 ID

    <fragment
    android:id="@+id/addEditUserFragment"
    android:name="com.sajtek.user.xprsmartadmin.ui.add_edit_user.AddEditUserFragment"
    android:label="add_edit_user_fragment"
    tools:layout="@layout/add_edit_user_fragment" />

【讨论】:

【参考方案6】:

尝试通过您的 Fragment 与您的导航进行通信。因此,只需简单地创建从适配器到 Fragment/Activity 的回调,然后从 Fragment/Activity 尝试像普通方式一样使用导航方法。

【讨论】:

【参考方案7】:

kotlin 中的示例

对不起我的英语

尝试做一个点击界面,在Adapter里面使用,可以获取item的位置

示例 ==> 接口

interface MyInterface 
    fun OnClickListener( string : String , position: Int, view: View)

如何在适配器内部使用

class ProductAdadapter(
    val context: Context,
    private var myInterface : MyInterface 
    ) : RecyclerView.Adapter<ProductAdadapter.ProductViewModel>() 


    override fun onCreateViewHolder(
        parent: ViewGroup,
        viewType: Int
    ): ProductViewModel 
        val view = LayoutInflater.from(context).inflate(R.layout.item_product_adapter, parent, false)
        return ProductViewModel(view)
    

    override fun getItemCount() =  product.size

    override fun getItemViewType(position: Int): Int 
        return super.getItemViewType(position)
    


    override fun onBindViewHolder(holder: ProductViewModel, position: Int) 
        holder.bindView(product[position])

        holder.mcvProductsAd.setOnClickListener
            myInterface .OnClickListener(product[position],position, it)
        
    


    class ProductViewModel(item: View) : RecyclerView.ViewHolder(item) 
        val mcvProductsAd = item.mcv_products_ad

        fun bindView(product: Product) 
            Glide.with(itemView.context).load(product.image).into(imageProduct)
        
    

然后在 Fragment 中制作一个工具

class ProductFragment : Fragment(), MyInterface 

    lateinit var productAdadapter: ProductAdadapter


    companion object 
        fun newInstance() = ProductFragment()
    

    private lateinit var viewModel: ProductViewModel

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? 
        return inflater.inflate(R.layout.product_fragment, container, false)
    

    override fun onActivityCreated(savedInstanceState: Bundle?) 
        super.onActivityCreated(savedInstanceState)
        viewModel = ViewModelProviders.of(this).get(ProductViewModel::class.java)

        viewModel.loadMessages().observe(viewLifecycleOwner, androidx.lifecycle.Observer 
            it?.let 
                grid.layoutManager = GridLayoutManager(context!!, 2)
                grid.adapter = ProductAdadapter(context!!, it, this)
            
        )

        mt_product_new.setOnClickListener  activity!!.onBackPressed() 
    

    override fun OnClickListener(string: String, position: Int, view: View) 
        Navigation.findNavController(it)
           .navigate(R.id.action_my_orders_fragment_to_offers_fragment, null)
         

    


【讨论】:

【参考方案8】:

如果你使用数据绑定,你只是

val 动作 = MessageListFragmentDirections.actionMessageListFragmentToSearchFragment() binding.root.findNavController().navigate(action)

【讨论】:

以上是关于RecyclerView 适配器中的导航组件的主要内容,如果未能解决你的问题,请参考以下文章

使用导航组件保存 RecyclerView 的滚动

RecyclerView 适配器 notifyDataSetChanged 停止花哨的动画

lateinit 属性适配器尚未初始化设置 RecyclerView 与 Fragment

RecyclerView 适配器中的 onBackPressed()

片段中的recyclerview的“RecyclerView:没有附加适配器;跳过布局”[重复]

RecyclerView 适配器中的空侦听器