Home > Mobile >  How to navigate to 2 different fragments using same adapter according to the type of model?
How to navigate to 2 different fragments using same adapter according to the type of model?

Time:12-10

My problem diagram

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
    }       
}
  • Related