16

I wrote the following piece of code in the adapter.

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

And this is may navigation 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>

but it won't work. Can anybody help?

salmanseifian
  • 1,082
  • 3
  • 9
  • 26

8 Answers8

43

You are using lambda which is itself a click listener. Check this Navigation Docs which has proper implementation of click listener using navigation id and createNavigationListener.

Use below code for your case.

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

OR, try this way

holder.itemView.setOnClickListener{ view ->
 view.findNavController().navigate(R.id.action_searchFragment_to_artistFragment)
}
Rajnish suryavanshi
  • 3,168
  • 2
  • 17
  • 23
  • 1
    Unfortunately, it didn't help. The problem is still there. – salmanseifian Jul 19 '19 at 21:08
  • holder.itemView.setOnClickListener( Navigation.createNavigateOnClickListener(R.id.productDetailsFragment) ); Yes this is works for me thanks – Sajib saha Mar 01 '22 at 09:36
  • Currently dealing with the same issue, appearently this is the accepted answer but I couldnt figure out where did you send the "artist.id" to other fragment. – Furkan Akcakaya May 02 '22 at 17:31
  • it throws "java.lang.IllegalStateException: View btnCompleted does not have a NavController set" to me – Olivér Raisz Mar 21 '23 at 19:06
  • This doesn't work very well, because view.findNavController() is behaving like a kind of iframe, replacing only the part that the RecyclerView is when I want it to actually go to the other fragment, but it must have solved someone's problem. – Macedo_Montalvão Aug 20 '23 at 06:53
8

I think its better to add this to the accepted answer:

holder.itemView.setOnClickListener(
 Navigation
 .createNavigateOnClickListener(R.id.action_searchFragment_to_artistFragment).onClick(holder.itemView)
)
A.sobhdel
  • 234
  • 4
  • 11
2

In your RecyclerView Adapter OnBindViewHolder method you can have it this way:

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

In the above, the destination is SalonDetailFragment whose id is salonDetailFragment and passing data as a Bundle to the destination.

My Navigation configuration

<?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>
ovicko
  • 2,242
  • 3
  • 21
  • 37
1

if you use viewBinding, this is batter

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)
}
Sukhi
  • 13,261
  • 7
  • 36
  • 53
  • For a more beautiful answer, you can format the part of the code as editing the answer. Then your answer will be easier to read. Welcome to stackOverflow :) – Ronaldo Albertini Mar 31 '20 at 11:31
1

Basically, you can do this in two ways.

  1. You can instantiate Navigation class and create navigation click listener

      private fun openEditUser() {
         binding.userName.setOnClickListener {
    
          Navigation.createNavigateOnClickListener(R.id.addEditUserFragment)
             }
         }
    
  2. You can get the view from the button or any other element that you use in the item layout and call on findNavController with navigate() method

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

    }

In both cases, you will need a reference from the ID of the action that will be used for navigation, you can see the ID in the navigation folder under the fragment XML tag

    <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" />
0

Try to communicate with your navigation through your Fragment. So just simply create callback from your adapter to Fragment/Activity and from Fragment/Activity try to use navigation methods like in ordinary way.

aLT
  • 326
  • 3
  • 9
0

Example in kotlin

sorry about my English

Try to make a click interface and use inside the Adadapter, with it you can take the position of the item

example ==> interface

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

How to use inside the adapter

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

afterwards and just make an implement inside the 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)
         }

    }

}
Jose alves
  • 31
  • 4
0

if you use databinding,you just

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