简体   繁体   中英

How to call a method in adapter from a fragment in kotlin?

I have been trying to call a function from fragment to adapter, but I can't approach it right. I want to invisible the button present in the fragment from adapter.

**My Adapter Code:**
package com.littleboo.brandlogo.Adapters

import android.R
import android.content.Context
import android.content.Intent
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.net.Uri
import android.os.Build
import android.os.VibrationEffect
import android.os.Vibrator
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.animation.Animation
import android.view.animation.AnimationUtils
import android.widget.Button
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.core.content.ContextCompat.getSystemService
import androidx.recyclerview.widget.RecyclerView
import com.littleboo.brandlogo.Fragments.QuizFragment
import com.littleboo.brandlogo.MainActivity
import com.littleboo.brandlogo.Models.Question
import com.littleboo.brandlogo.databinding.ActivityMainBinding.inflate
import com.littleboo.brandlogo.databinding.FragmentQuizBinding
import kotlinx.coroutines.NonDisposableHandle.parent


class QuestionAdap(val context: Context, val question: Question) :
RecyclerView.Adapter<QuestionAdap.OptionViewHolder>() {
    var index = 1
    var score = 0
    val animShake: Animation = AnimationUtils.loadAnimation(context, com.littleboo.brandlogo.R.anim.shake)



    private var options: List<String> = listOf(question.option1, question.option2, question.option3, question.option4)

    inner class OptionViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView){
        var optionView = itemView.findViewById<TextView>(com.littleboo.brandlogo.R.id.quiz_option)
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): OptionViewHolder {
        val view = LayoutInflater.from(context).inflate(com.littleboo.brandlogo.R.layout.quizoptions, parent, false)
        return  OptionViewHolder(view)
    }

    override fun onBindViewHolder(holder: OptionViewHolder, position: Int) {
        holder.optionView.text = options[position]
        holder.itemView.setOnClickListener {
            question.userAnswer = options[position]
            notifyDataSetChanged()
        }

        if(question.userAnswer == options[position] && question.userAnswer == question.answer){
            holder.itemView.setBackgroundResource(com.littleboo.brandlogo.R.drawable.option_item_selected_bg)
            score += 10
            Toast.makeText(context,"Score is $score", Toast.LENGTH_SHORT).show()
        }

        else if(question.userAnswer == options[position] && question.userAnswer != question.answer){
            holder.itemView.setBackgroundResource(com.littleboo.brandlogo.R.drawable.wrong_option_item_selected_bg)
            holder.itemView.startAnimation(animShake)
        }

        else{
            holder.itemView.setBackgroundResource(com.littleboo.brandlogo.R.drawable.non_option_item_selected_bg)
        }
    }

    override fun getItemCount(): Int {
        return options.size
    }


}

My Quiz Fragment Code:

package com.littleboo.brandlogo.Fragments

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.swiperefreshlayout.widget.CircularProgressDrawable
import com.bumptech.glide.Glide
import com.google.firebase.firestore.FirebaseFirestore
import com.littleboo.brandlogo.Adapters.QuestionAdap
import com.littleboo.brandlogo.Models.Question
import com.littleboo.brandlogo.Models.quizmodel
import com.littleboo.brandlogo.R
import com.littleboo.brandlogo.databinding.FragmentQuizBinding


class QuizFragment : Fragment(){

    lateinit var binding: FragmentQuizBinding
    var quizzes: MutableList<quizmodel>? = null
    private var questions = mutableMapOf<String, Question>()
    private lateinit var mArraylist: ArrayList<Question>
    var index = 1
    private lateinit var mfirestore: FirebaseFirestore
    private lateinit var mrecycler: RecyclerView
    lateinit var myadapter: QuestionAdap

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    }


    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        binding = FragmentQuizBinding.inflate(layoutInflater)
        return binding.root
    }




    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        mrecycler = binding.optionList
        mrecycler.layoutManager
        myadapter = QuestionAdap(requireContext(),Question())



        mArraylist = arrayListOf()
        questions.map { it.key to it.value }.shuffled().toMap()
        setUpFirestore()
        setUpEventListener()
    }
    override fun onDestroy() {
        super.onDestroy()
        mfirestore.terminate()
//        finish()
    }

    private fun setUpEventListener() {


        binding.nextbtn.setOnClickListener {
            index++
            bindViews()
        }

//        binding.btnSubmit.setOnClickListener {
//            Log.d("FINALQUIZ", questions.toString())
//            val intent = Intent(this, ResultActivity::class.java)
//            val json = Gson().toJson(quizzes!![0])
//            intent.putExtra("QUIZ", json)
//            startActivity(intent)
//            finish()
//        }
    }

    private fun setUpFirestore() {
        mfirestore = FirebaseFirestore.getInstance()
        val quizTitle = activity?.intent?.getStringExtra("title")
        if (quizTitle != null) {
            mfirestore.collection("Quizes").whereEqualTo("title", quizTitle)
                .get()
                .addOnSuccessListener {
                    if (it != null && !it.isEmpty) {
                        quizzes = it.toObjects(quizmodel::class.java)
                        questions = quizzes!![0].questions
                        shuffle()
                        bindViews()
                    }

                }
        }
    }

    private fun bindViews() {
//        btnPrevious.visibility = View.GONE
//        binding.btnSubmit.visibility = View.GONE
//        binding.btnNext.visibility = View.GONE

//        if (index == 1) { //first question
//            binding.btnNext.visibility = View.VISIBLE
//        } else if (index == questions!!.size) { // last question
//            binding.btnSubmit.visibility = View.VISIBLE
////            btnPrevious.visibility = View.VISIBLE
//        } else { // Middle
////            btnPrevious.visibility = View.VISIBLE
//            binding.btnNext.visibility = View.VISIBLE
//        }

        val circularProgressDrawable = CircularProgressDrawable(requireContext())
        circularProgressDrawable.strokeWidth = 8f
//        circularProgressDrawable.colorFilter = ("#ac5fe1")
        circularProgressDrawable.centerRadius = 30f
        circularProgressDrawable.start()

        val question = questions!!["question$index"]
        question?.let {
            Glide.with(this).load(it.imagequiz).placeholder(circularProgressDrawable).into(binding.imagequiz)
            val optionAdapter = QuestionAdap(requireContext(), it)
            mrecycler.layoutManager = LinearLayoutManager(requireContext())
            mrecycler.adapter = optionAdapter
            mrecycler.setHasFixedSize(true)
        }
    }


    private fun shuffle() {
        val keys = questions.keys.toMutableList().shuffled()
        val values = questions.values.toMutableList().shuffled()
        keys.forEachIndexed { index, key ->
            questions[key] = values[index]
        }

    }
}

I tried calling fragment in adapter like: QuizFragment().binding.btnxt.visibility = View.Visible

in BindViewHolder function.

Thank You

You can use kotlin lambda function to achieve it. Like this

class QuestionAdap(val context: Context, val question: Question, var onItemClicked: ((boolean) -> Unit))

call onItemClicked in your adapter where you want it and in fragment

myadapter = QuestionAdap(requireContext(),Question()) { boolean ->
 if (boolean) {
  // hide/show
} else {
  //hide/show
}
}

You can use the Callback functions of kotlin in your fragment, which will be passed into your adapter. So whenever you invoke that callback from your adapter, it will be triggered in your fragment.

Step 1: Create a method like the one below in your fragment.

private fun showHideButtonFromAdapter (
        isButtonVisible: Boolean
    ) {
     // set your button visibility according to isButtonVisible value. 
}

Step 2: pass a method from your fragment to adapter as argument

val adapter = YourAdapter(::showHideButtonFromAdapter)
// set above adapter in your recycler view.

Step 3: In your adapter invoke that callback function like the one below.

class ColorPickerAdapter constructor(
    private val onItemClicked: (Boolean) -> Unit
) : RecyclerView.Adapter<YourAdapter.ViewHolder>() {
    // your other adapter methods here
    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        onItemClicked.invoke(pass true or false as per your requirement)
        // above invocation will trigger an event in the fragment.
    }
}

In your adapter there need to be instance of your fragment, so change it like:

class QuestionAdap(val context: Context, val question: Question, fragment: Fragment) :
RecyclerView.Adapter<QuestionAdap.OptionViewHolder>() {

Then you can call your fragment by simply writing fragment in your adapter like:

    override fun onBindViewHolder(holder: OptionViewHolder, position: Int) {
        holder.optionView.text = options[position]
        holder.itemView.setOnClickListener {
            question.userAnswer = options[position]
            notifyDataSetChanged()
        }
        //Example
        fragment.shuffle()

And you need to send this fragment instance when you create it's adapter, so in your fragment use this:

myadapter = QuestionAdap(requireContext(),Question(), this)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM