簡體   English   中英

使用帶有 Kotlin 的接口回調方法將數據從適配器傳遞到活動

[英]Pass data from adapter to activity using interface callback method with Kotlin

我已通讀此Kotiln: pass data from adapter to activity並嘗試從給出的答案中選擇選項 1。

我有一個不同級別的游戲。 我使用 gridlayout 中的以下 itemview 將所有級別發送到回收站視圖

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:paddingTop="6dp"
    android:paddingBottom="6dp"
    app:layout_constraintHorizontal_chainStyle="spread">

    <RatingBar
        android:id="@+id/ratingBar"
        style="@style/Widget.AppCompat.RatingBar.Small"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginTop="2dp"
        android:layout_marginEnd="8dp"
        android:isIndicator="true"
        android:numStars="3"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/button" />

    <Button
        android:id="@+id/button"
        android:layout_width="90dp"
        android:layout_height="60dp"
        android:layout_marginStart="8dp"
        android:layout_marginEnd="8dp"
        android:backgroundTint="@color/game_button_color"
        android:textColor="@color/game_button_text_color"
        app:autoSizeTextType="uniform"
        app:layout_constraintDimensionRatio="1"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

我的適配器目前看起來像這樣;

    package com.maxcell.sumitup

import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.RatingBar
import androidx.core.content.ContextCompat.startActivity
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView


class LevelsAdaptor(private val callbackInterface:CallbackInterface) : ListAdapter<Levels, LevelsAdaptor.LevelsViewHolder>(LevelsComparator()) {

    interface CallbackInterface {
        fun passDataCallback(main:Int,sub: Int,star: Int)
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): LevelsViewHolder {
        return LevelsViewHolder.create(parent)
    }

    override fun onBindViewHolder(holder: LevelsViewHolder, position: Int) {
        val current = getItem(position)
        holder.bind(
            current.id,
            current.mainLevel,
            current.subLevel,
            current.stars,
            current.unlocked
        )

    }


    class LevelsViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {



        private val btn: Button = itemView.findViewById(R.id.button)
        private val rating: RatingBar = itemView.findViewById(R.id.ratingBar)
        private val myContext = itemView.context
        //private val myContext: Context = sumView.context
        fun bind(ID: Int, ML: Int, SL: Int, Stars: Int, Unlocked: Boolean) {

            btn.text = ID.toString()
            btn.setTag(R.id.mainLevel, ML)
            btn.setTag(R.id.subLevel, SL)
            btn.setTag(R.id.visualLevel, ID)
            btn.setTag(R.id.currentLevelStars, Stars)
            rating.rating = Stars.toFloat()
            if (Unlocked==true){btn.isEnabled=true; btn.isClickable=true}else{btn.isEnabled=false; btn.isClickable=false}

            itemView.setOnClickListener {
                //Set your codes about intent here
                CallbackInterface.passDataCallback(ML,SL,Stars)
            }

        }



        companion object {
            fun create(parent: ViewGroup): LevelsViewHolder {
                val view: View = LayoutInflater.from(parent.context)
                    .inflate(R.layout.rv_storymode_items, parent, false)
                return LevelsViewHolder(view)
            }
        }
    }

    class LevelsComparator : DiffUtil.ItemCallback<Levels>() {
        override fun areItemsTheSame(oldItem: Levels, newItem: Levels): Boolean {
            return oldItem.id == newItem.id
        }

        override fun areContentsTheSame(oldItem: Levels, newItem: Levels): Boolean {
            return oldItem == newItem
        }
    }
}

我目前遇到的問題是我的同伴 object,因為我在我的 onbindviewholder 中包含了回調接口,它需要我在返回中包含一個參數。 我正在努力解決這個問題並了解此時應包含哪些參數

我也沒有100%關注它。 在鏈接中我分享了接口 function 被稱為 passDataCallback() 然后他們在 onBindViewHolder 中使用 passResultCallback()。 如果我使用 passResultCallback 它不會解決所以我不知道我是否做錯了什么或者它是否真的是我在上面的適配器中寫的那樣

我還沒有在我的活動中收集這些數據,因為希望至少首先正確編寫適配器,如果人們認為我需要完全重新考慮該方法,我會聽取該建議。

這是持有recyclerview 的活動。 這是我認為我應該為結果啟動新活動的地方

package com.maxcell.sumitup

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.Button
import android.widget.Toast
import androidx.activity.viewModels
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.view.isVisible
import androidx.fragment.app.FragmentTransaction
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import kotlinx.android.synthetic.main.activity_story_levels.*

class StoryLevels : AppCompatActivity(), View.OnClickListener {

    private lateinit var storyView: RecyclerView
    val numbers = mutableListOf(1,2,3,4,5,6,7,8,9,10)
    lateinit var btn1: Button
    lateinit var btn2: Button
    lateinit var btn3: Button
    lateinit var btn4: Button
    lateinit var btn5: Button
    lateinit var btn6: Button
    lateinit var btn7: Button
    lateinit var btn8: Button
    lateinit var btn9: Button
    lateinit var btn10: Button

    lateinit var popupLayout: ConstraintLayout
    lateinit var popupBTNstart:Button
    lateinit var popupBTNexit:Button




    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_story_levels)

        storyView = findViewById(R.id.rv_storymode)

        btn1 = findViewById(R.id.button2)
        btn2 = findViewById(R.id.button3)
        btn3 = findViewById(R.id.button4)
        btn4 = findViewById(R.id.button5)
        btn5 = findViewById(R.id.button6)
        btn6 = findViewById(R.id.button7)
        btn7 = findViewById(R.id.button8)
        btn8 = findViewById(R.id.button9)
        btn9 = findViewById(R.id.button10)
        btn10 = findViewById(R.id.button11)

        btn1.text = numbers[0].toString()
        btn2.text = numbers[1].toString()
        btn3.text = numbers[2].toString()
        btn4.text = numbers[3].toString()
        btn5.text = numbers[4].toString()
        btn6.text = numbers[5].toString()
        btn7.text = numbers[6].toString()
        btn8.text = numbers[7].toString()
        btn9.text = numbers[8].toString()
        btn10.text = numbers[9].toString()

        btn1.setOnClickListener(this)
        btn2.setOnClickListener(this)
        btn3.setOnClickListener(this)
        btn4.setOnClickListener(this)
        btn5.setOnClickListener(this)
        btn6.setOnClickListener(this)
        btn7.setOnClickListener(this)
        btn8.setOnClickListener(this)
        btn9.setOnClickListener(this)
        btn10.setOnClickListener(this)

        popupLayout = findViewById(R.id.layout_pregame_intro)
        popupLayout.isVisible = false
        popupBTNexit = findViewById(R.id.popup_btn_exit)

        val levelsViewModel: LevelsViewModel by viewModels {
            LevelsViewModelFactory((application as MyApplication).repository2)}

        val adapter = LevelsAdaptor()
        rv_storymode.adapter = adapter
        rv_storymode.layoutManager = GridLayoutManager(applicationContext, 4);

        levelsViewModel.level1.observe(this) { newValue ->
            // Update the cached copy of the words in the adapter.
            newValue.let { adapter.submitList(it) }
        }
    }

    fun testMessage(){
        Toast.makeText(applicationContext,"this is toast message", Toast.LENGTH_SHORT).show()
    }
    override fun onClick(v: View?) {

        val levelsViewModel: LevelsViewModel by viewModels {
            LevelsViewModelFactory((application as MyApplication).repository2)}

        val adapter = LevelsAdaptor()
        rv_storymode.adapter = adapter
        rv_storymode.layoutManager = GridLayoutManager(applicationContext, 4);

        if (v != null) {
            when (v.id){
                R.id.button2->{
                    levelsViewModel.level1.observe(this) { newValue ->
                        // Update the cached copy of the words in the adapter.
                        newValue.let { adapter.submitList(it) }}
                }
                R.id.button3->{
                    levelsViewModel.level2.observe(this) { newValue ->
                        // Update the cached copy of the words in the adapter.
                        newValue.let { adapter.submitList(it) }}}
                R.id.button4->{
                    levelsViewModel.level3.observe(this) { newValue ->
                        // Update the cached copy of the words in the adapter.
                        newValue.let { adapter.submitList(it) }}}
                R.id.button5->{
                    levelsViewModel.level4.observe(this) { newValue ->
                        // Update the cached copy of the words in the adapter.
                        newValue.let { adapter.submitList(it) }}}
                R.id.button6->{
                    levelsViewModel.level5.observe(this) { newValue ->
                        // Update the cached copy of the words in the adapter.
                        newValue.let { adapter.submitList(it) }}}
                R.id.button7->{
                    levelsViewModel.level6.observe(this) { newValue ->
                        // Update the cached copy of the words in the adapter.
                        newValue.let { adapter.submitList(it) }}}
                R.id.button8->{
                    levelsViewModel.level7.observe(this) { newValue ->
                        // Update the cached copy of the words in the adapter.
                        newValue.let { adapter.submitList(it) }}}
                R.id.button9->{
                    levelsViewModel.level8.observe(this) { newValue ->
                        // Update the cached copy of the words in the adapter.
                        newValue.let { adapter.submitList(it) }}}
                R.id.button10->{
                    levelsViewModel.level9.observe(this) { newValue ->
                        // Update the cached copy of the words in the adapter.
                        newValue.let { adapter.submitList(it) }}}
                R.id.button11->{
                    levelsViewModel.level10.observe(this) { newValue ->
                        // Update the cached copy of the words in the adapter.
                        newValue.let { adapter.submitList(it) }}}
            }
        }
    }
}

預期結果

Recyclerview 充滿了包含評分欄的按鈕(1-3 星取決於他們上次玩該級別時的表現) -這很有效

當我單擊其中一個按鈕時,我的活動應該知道該級別的主級別、子級別和當前星星

然后我將開始一個新的活動,將結果傳遞到我的迷你游戲中

注意:你會注意到我設置了按鈕標簽。 這是我正在遵循的一種方法,如果使用界面效果很好並且人們同意它是最好的方法,則可以將其刪除

...............編輯.................

更新了適配器代碼,以便在適配器級別而不是在 onbindviewholder 中初始化接口。

但是,我仍然無法使以下工作;

itemView.setOnClickListener {
                //Set your codes about intent here
                CallbackInterface.passDataCallback(ML,SL,Stars)
            }

具體問題是“passDataCallback”將無法解析,即未解析的引用:passDataCallback。 我相信它現在確實類似於頂部鏈接中共享的方法。 我不得不承認我是界面新手。 我只用過他們在道內約會

我已經嘗試將界面移動到 LevelsViewHolder - 這並沒有解決它。

將您的適配器更改為此

class LevelsAdaptor(private val onClick:(id:Int)->Unit) : ListAdapter<Levels, LevelsAdaptor.LevelsViewHolder>(LevelsComparator()) {

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

    override fun onBindViewHolder(holder: LevelsViewHolder, position: Int) {
        val current = getItem(position)
        holder.bind(
            current.id,
            current.mainLevel,
            current.subLevel,
            current.stars,
            current.unlocked
        )
    }
    
    inner class LevelsViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        private val btn: Button = itemView.findViewById(R.id.button)
        private val rating: RatingBar = itemView.findViewById(R.id.ratingBar)
        private val myContext = itemView.context
        //private val myContext: Context = sumView.context
        fun bind(ID: Int, ML: Int, SL: Int, Stars: Int, Unlocked: Boolean) {
            btn.text = ID.toString()
            btn.setTag(R.id.mainLevel, ML)
            btn.setTag(R.id.subLevel, SL)
            btn.setTag(R.id.visualLevel, ID)
            btn.setTag(R.id.currentLevelStars, Stars)
            rating.rating = Stars.toFloat()
            if (Unlocked==true){btn.isEnabled=true; btn.isClickable=true}else{btn.isEnabled=false; btn.isClickable=false}
            itemView.setOnClickListener {
                //Set your codes about intent here
                onClick(ID)
            }
        }
    }

    class LevelsComparator : DiffUtil.ItemCallback<Levels>() {
        override fun areItemsTheSame(oldItem: Levels, newItem: Levels): Boolean {
            return oldItem.id == newItem.id
        }

        override fun areContentsTheSame(oldItem: Levels, newItem: Levels): Boolean {
            return oldItem == newItem
        }
    }
}

你在你的活動中初始化適配器

val adapter = LevelsAdaptor(){id->
    //TODO do something with id passed from adapter, e.g. create new fragment
}

我還建議使用Jetpack Navigation ,您可以使用詳細視圖作為進入關卡

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM