9
votes

Composant de navigation dans l'adaptateur RecyclerView

J'ai écrit le morceau de code suivant dans l'adaptateur.

 ...
    <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>

Et voici la navigation xml:

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

mais cela ne fonctionnera pas. Quelqu'un peut-il aider?


2 commentaires

Êtes-vous sûr que holder.itemView.setOnClickListener est dans SearchFragment ?


@JohnJoe Oui, j'en suis sûr.


7 Réponses :


20
votes

Vous utilisez lambda qui est lui-même un écouteur de clics. Vérifiez cette documentation de navigation qui a une implémentation correcte de l'écouteur de clic à l'aide de l'ID de navigation et de createNavigationListener.

Utilisez le code ci-dessous pour votre cas.

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

OU, essayez de cette façon

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


2 commentaires

Malheureusement, cela n'a pas aidé. Le problème est toujours là.


La deuxième option a parfaitement fonctionné pour moi



0
votes

Essayez de communiquer avec votre navigation dans votre Fragment. Créez simplement un rappel de votre adaptateur vers Fragment / Activity et depuis Fragment / Activity, essayez d'utiliser des méthodes de navigation comme de manière ordinaire.


0 commentaires

1
votes

Dans votre méthode OnBindViewHolder adaptateur RecyclerView, vous pouvez l'avoir de cette façon:

<?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>

Dans ce qui précède, la destination est SalonDetailFragment dont l'id est salonDetailFragment et transmet les données en tant que Bundle à la destination.

Ma configuration de navigation

        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);     
        });



0
votes

Exemple en kotlin

Désolé de mon anglais

Essayez de créer une interface de clic et de l'utiliser à l'intérieur de l'adaptateur, avec elle, vous pouvez prendre la position de l'élément

exemple ==> interface

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)
         }

    }

}

Comment utiliser à l'intérieur de l'adaptateur

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)
        }
    }
}

ensuite et créez simplement un outil à l'intérieur du fragment

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


0 commentaires

2
votes

Je pense qu'il vaut mieux ajouter ceci à la réponse acceptée:

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


1 commentaires

Voilà la réponse.



0
votes

si vous utilisez viewBinding, c'est la pâte

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)
}


1 commentaires

Pour une réponse plus belle, vous pouvez formater la partie du code en éditant la réponse. Ensuite, votre réponse sera plus facile à lire. Bienvenue dans stackOverflow :)



1
votes

Fondamentalement, vous pouvez le faire de deux manières.

  1. Vous pouvez instancier la classe de navigation et créer un écouteur de clic de navigation

        <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" />
    
  2. Vous pouvez obtenir la vue à partir du bouton ou de tout autre élément que vous utilisez dans la disposition de l'élément et appeler findNavController avec la méthode navigate ()

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

    }

Dans les deux cas, vous aurez besoin d'une référence de l'ID de l'action qui sera utilisée pour la navigation, vous pouvez voir l'ID dans le dossier de navigation sous la balise XML fragment

  private fun openEditUser() {
     binding.userName.setOnClickListener {

      Navigation.createNavigateOnClickListener(R.id.addEditUserFragment)
         }
     }


0 commentaires