Данные Firestore из RecyclerView на Kotlin

Рейтинг: 0Ответов: 1Опубликовано: 11.04.2023

У меня есть список RecyclerView в котором я отображаю все документы (у каждого документа есть своя коллекция с данными) из Firestore, и такой вопрос, как при нажатии на элемент списка отобразить его соответствующие данные в новом фрагменте

ViewModel

class MainViewModel: ViewModel() {
private val db = FirebaseFirestore.getInstance()
private val auth = FirebaseAuth.getInstance()
private val documentsLiveData = MutableLiveData<List<Card>>()

fun getDocuments() {
    if (auth.currentUser != null){
        db.collection("cards")
            .get()
            .addOnSuccessListener { documents ->
                val cardList = mutableListOf<Card>()
                for (document in documents) {
                    val card = document.toObject(Card::class.java)
                    cardList.add(card)
                }
                documentsLiveData.value = cardList
            }
            .addOnFailureListener { exception ->
                Log.e("Document error", exception.message.toString())
            }
    }
    else{
        Log.e("Document error", "Toast error")
    }

}

fun getDocumentsLiveData(): LiveData<List<Card>> {
    return documentsLiveData
}

}

Adapter

class CardAdapter(private val context: Context,
              private val list: List<Card>) : RecyclerView.Adapter<CardAdapter.MyViewHolder>() {

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
    val view = LayoutInflater.from(parent.context).inflate(R.layout.item_layout, parent, false)
    return MyViewHolder(view)
}

override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
    val item = list[position]
    holder.itemView.card_name.text = item.name
    holder.itemView.card_description.text = item.description
    Glide.with(context)
        .load(item.img)
        .into(holder.itemView.card_img)
}

override fun getItemCount(): Int {
    return list.size

}

class MyViewHolder(view: View) : RecyclerView.ViewHolder(view){

}

}

MainFragment

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)

    viewModel = ViewModelProvider(this)[MainViewModel::class.java]

    viewModel.getDocumentsLiveData().observe(viewLifecycleOwner) { cardList ->
        binding.progBar.visibility = View.GONE
        val adapter = CardAdapter(requireContext(), cardList)
        binding.mainRecycler.adapter = adapter
    }
    viewModel.getDocuments()
}

Ответы

▲ 1

Обработка нажатия по элементу списка RecyclerView требует последующей передачи информации об элементе в активность/фрагмент. Это можно сделать двумя способами:

  1. Через интерфейс. Ниже пример интерфейса:

    interface IClickListener {
     fun openItem(item: Card)
    }
    

дальше в конструкторе адаптера списка добавляем параметр слушателя:

class CardAdapter(
    ...
    private val listener: IClickListener
) : RecyclerView.Adapter<CardAdapter.MyViewHolder>() {

...
}

добавляем обработку нажатия на элемент списка:

holder.itemView.setOnClickListener {
   listener.openItem(item)
}

в фрагменте добавляем наш интерфейс:

class SomeFragment : Fragment(), IClickListener {

...

    override fun delete(card:Card){
     
    }

}

и во время создания адаптера добавляем параметр:

CardAdapter(requireContext(), cardList, this@SomeFragment)
  1. Второй вариант - добавляем колбек в адаптер:

     class CardAdapter(
     ...,
     val listener: (Card) -> Unit
     ) : RecyclerView.Adapter<CardAdapter.MyViewHolder>() {
    
     ...
    
     }
    

в обработке нажатий добавляем вызов:

holder.itemView.setOnLongClickListener {
   listener.invoke(item)
}

и адаптер у нас превращается в такой:

CardAdapter(requireContext(), cardList){
// здесь приходит тоже Card
}

ну и дальше у вас есть модель нажатого элемента списка которую вы можете использовать по назначению.

P.S. я думаю если у вас не используется переменная адаптера, то можно сам адаптер напрямую инициализировать так:

binding.mainRecycler.adapter = CardAdapter(requireContext(), cardList)