In my program i have a RecyclerView with adapter, in which i'm checking which element of RecyclerView is clicked.
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val currentBreakfast = breakfastList[position]
holder.breakfastTitle.text = context.getText(currentBreakfast.breakfastStringResourceId)
holder.breakfastImage.setImageResource(currentBreakfast.breakfastImageResourceId)
holder.breakfastImage.setOnClickListener {
holder.itemView.findNavController().navigate(R.id.action_breakfastFragment_to_DetailsFragment)
showDetails(currentBreakfast)
}
}
I want to pass the data about specific clicked element, such as imageId, stringId, Name, etc. to another fragment DetailsFragment in which i would like to display further data
How can i do it?
CodePudding user response:
You need to send your fragment to the adapter from where you are calling i guess it's breakfastFragment, just add this
to it:
YourAdapter(
requireActivity(),
breakfastList,
this
)
And your Adapter get that fragment
:
open class YourAdapter(
private val context: Context,
private var breakfastList: ArrayList<Breakfast>,
private val fragment: Fragment
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
And you can use that fragment
to be able to navigate from it:
holder.breakfastImage.setOnClickListener {
// create a bundle to hold data you want to send
val bundle = bundleOf(
"imageId" to currentBreakfast.imageId,
"stringId" to currentBreakfast.stringId,
"name" to currentBreakfast.name
)
// add this bundle when you move to another fragment.
fragment.findNavController().navigate(R.id.action_breakfastFragment_to_DetailsFragment, bundle)
}
In another fragment get that value and see them in the Log like below:
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
arguments?.let {
if (it["imageId"] != null) {
Log.e("imageId", it.getString("imageId")!!.toString())
}
if (it["stringId"] != null) {
Log.e("stringId", it.getString("stringId")!!.toString())
}
if (it["name"] != null) {
Log.e("name", it.getString("name")!!.toString())
}
}
return inflater.inflate(R.layout.fragment_question_stats, container, false)
}
P.S. I just made up some variable and class names because you did not share them, just change it with yours correct ones.
CodePudding user response:
There are several ways to it.
I suggest you have a look at this answer (the accepted one) : How to pass data from adapter to fragment?
And then go to the section called "A more Kotlin way to do it is to ignore interfaces and just pass a function instead".
This is the approach I also use myself.
Here is an exampe of how my Adapter for the RecyclerView is defined:
class ReportAdapter(var reports: List<Report>,val clickFunc : (Report) -> (Unit)) : RecyclerView.Adapter<ReportAdapter.ViewHolder>() {...}
Then you need to attach the callback function to a click listener inside your viewholder - in my example it looks like this (every item in the list has a cardview - defined in the xml file):
itemView.report_cardview_item.setOnClickListener {
clickFunc(report)
}
Then in the callback function you pass to the RecylerView Adapter you can navigate to a details fragment with the relevant data - one of my callback functions (which is passed to the Adapter upon creation) simply looks like this (defined in the Fragment that "owns" the RecyclerView):
private fun reportClicked(report:Report)
{
val action = ReportsFragmentDirections.actionNavReportsToReportDetailFragment(report)
findNavController().navigate(action)
}
(here using my navigation graph to create an Action to use for the NavController)
My adapter is easily initialized with some data and a reference to the callback function:
adapter = ReportAdapter(reports,::reportClicked)