I want to navigate 2 different fragments using same adapter according to the type of my model. But my problem is I can't handle onItemClicked with two different models. As you can see:
private val onItemClicked: (WordsWithMeanings) -> Unit
FavoriteFragment
class FavoriteFragment : Fragment(R.layout.fragment_favorite) {
private var _binding: FragmentFavoriteBinding? = null
private val binding get() = _binding!!
private val viewModel: WordViewModel by activityViewModels {
WordViewModelFactory(
(activity?.application as WordApplication).database.wordDao()
)
}
private lateinit var adapter: FavoriteListAdapter
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = FragmentFavoriteBinding.inflate(inflater)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
adapter = FavoriteListAdapter(viewModel) {
val action = FavoriteFragmentDirections.actionFavouriteFragmentToWordDetailFragment(it).
this.findNavController().navigate(action)
}
binding.recyclerView.adapter = adapter
viewModel.allWordsWithMeanings.observe(this.viewLifecycleOwner) { items ->
items.let {
for (i in items) {
if (i.word.isFavorite == true) {
adapter.mData.add(i)
}
}
}
favoriteFragmentFavoriteStatus()
}
viewModel.allProverbs.observe(this.viewLifecycleOwner) { items ->
items.let {
for (i in items) {
if (i.isFavorite == true) {
adapter.mData.add(i)
}
}
}
}
binding.recyclerView.layoutManager = LinearLayoutManager(this.context)
}
}`
```
FavoriteListAdapter
private const val WORD_VIEW_TYPE = 0
private const val PROVERB_VIEW_TYPE = 1
class FavoriteListAdapter(
private val viewModel: WordViewModel,
private val onItemClicked: (WordsWithMeanings) -> Unit
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
val mData = mutableListOf<Any>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val inflater = LayoutInflater.from(parent.context)
return when (viewType) {
WORD_VIEW_TYPE -> WordItemViewHolder(
FavoriteItemsBinding.inflate(
inflater,
parent,
false
)
)
PROVERB_VIEW_TYPE -> ProverbItemViewHolder(
FavoriteItemsBinding.inflate(
inflater,
parent,
false
)
)
else -> throw IllegalArgumentException("Invalid view type")
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val element = mData[position]
when (getItemViewType(position)) {
WORD_VIEW_TYPE -> {
holder.itemView.setOnClickListener {
onItemClicked(element as WordsWithMeanings)
}
(holder as WordItemViewHolder).bind(
element as WordsWithMeanings,
viewModel
)
}
PROVERB_VIEW_TYPE -> {
(holder as ProverbItemViewHolder).bind(element as Proverb, viewModel)
}
}
}
class WordItemViewHolder(private var binding: FavoriteItemsBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bind(favoriteWordsWithMeanings: WordsWithMeanings, viewModel: WordViewModel) {
binding.apply {
title.text = favoriteWordsWithMeanings.word.word
content.text = favoriteWordsWithMeanings.means[0].wordMean
favoriteButton.isChecked =
favoriteWordsWithMeanings.word.isFavorite == true
favoriteButton.setOnClickListener {
if (favoriteButton.isChecked) {
favoriteButton.isChecked = true
viewModel.updateFavoriteWord(favoriteWordsWithMeanings, true)
} else {
favoriteButton.isChecked = false
viewModel.updateFavoriteWord(favoriteWordsWithMeanings, false)
}
}
}
}
}
class ProverbItemViewHolder(private var binding: FavoriteItemsBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bind(favoriteProverb: Proverb, viewModel: WordViewModel) {
binding.apply {
title.text = favoriteProverb.proverb
content.text = favoriteProverb.proverbMean
favoriteButton.isChecked =
favoriteProverb.isFavorite == true
favoriteButton.setOnClickListener {
if (favoriteButton.isChecked) {
favoriteButton.isChecked = true
viewModel.updateFavoriteProverb(favoriteProverb, true)
} else {
favoriteButton.isChecked = false
viewModel.updateFavoriteProverb(favoriteProverb, false)
}
}
}
}
}
override fun getItemCount(): Int {
return mData.size
}
override fun getItemViewType(position: Int): Int {
return when (mData[position]) {
is WordsWithMeanings -> WORD_VIEW_TYPE
is Proverb -> PROVERB_VIEW_TYPE
else -> throw IllegalArgumentException("Unsupported type")
}
}
}
So I only navigate to one fragment. What I want to do is if clicked item is 'WordsWithMeanings' navigate to WordDetailFragment, if clicked item is 'Proverb' navigate to ProverbDetailFragment. Is there proper way to do this?
SOLUTION:
Firstly I changed this
private val onItemClicked: (WordsWithMeanings) -> Unit
to this
private val onItemClicked: (Any) -> Unit
After that using action like this solved my problem.
action = if (it is WordsWithMeanings) {
FavoriteFragmentDirections.actionFavouriteFragmentToWordDetailFragment(it)
} else {
FavoriteFragmentDirections.actionFavouriteFragmentToProverbDetailFragment(it as Proverb)
}
this.findNavController().navigate(action as NavDirections)
CodePudding user response:
You are passing a WordsWithMeaning item in your adapter onItemClicked callback. You can check if the item passed to your callback is of WordsWithMeaning type or Proverb type and then act accordingly:
adapter = FavoriteListAdapter(viewModel) {
val action = if (it is Proverb) {
// navigate to proverb details
} else {
// navigate to word details
}
}