Why isn't my click listener working for a dynamically populated grid view in Android using Kotlin?

huangapple go评论57阅读模式
英文:

Why isn't my click listener working for a dynamically populated grid view in Android using Kotlin?

问题

如何为动态填充的 GridView 设置项点击事件监听器?

我已经为 gridView 项设置了点击监听器。它们在 XML 文件中是可点击的。然而,点击操作没有触发。我尝试在 onCreate 方法和 display drinks 方法中设置了 onclick 监听器,但都没有起作用。使用 setOnClickListener 得到了相同的结果。

似乎点击监听器可能没有正确附加或初始化。是否有特定的位置或方法可以设置监听器以确保它正常工作?也许问题在于 GridView 被动态填充。这可能是导致问题的原因吗?

我该如何解决这个问题?

class DrinkAdapter(private val drinks: List<Drink>) : BaseAdapter() {

    override fun getCount(): Int {
        return drinks.size
    }

    override fun getItem(position: Int): Any {
        return drinks[position]
    }

    override fun getItemId(position: Int): Long {
        return position.toLong()
    }

    override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
        val view = convertView ?: LayoutInflater.from(parent?.context)
            .inflate(R.layout.grid_item_drink, parent, false)

        val drink = drinks[position]

        val imageView = view.findViewById<ImageView>(R.id.drinkImage)
        val textView = view.findViewById<TextView>(R.id.drinkName)

        imageView.viewTreeObserver.addOnGlobalLayoutListener {
            val width = imageView.width
            val height = imageView.height

            GlideApp.with(imageView)
                .load(drink.getImageUrl())
                .override(width, height)
                .placeholder(R.drawable.placeholder_image)
                .error(R.drawable.error_image)
                .into(imageView)
        }

        textView.text = drink.name

        return view
    }
}

class BrowseDrinksActivity : AppCompatActivity() {

    private lateinit var gridView: GridView
    private lateinit var drinks: List<Drink>

    private val apiService: BrowseApiService by lazy {
        Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
            .create(BrowseApiService::class.java)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.browse_drinks)
        supportActionBar?.setDisplayHomeAsUpEnabled(true)

        gridView = findViewById(R.id.gridView)
        gridView.onItemClickListener =
            AdapterView.OnItemClickListener { _, _, position, _ ->
                val drink = drinks[position]
                showDrinkDetails(drink)
            }

        fetchDrinks()
    }

    private fun fetchDrinks() {
        val call: Call<List<Drink>> = apiService.getDrinks()
        call.enqueue(object : Callback<List<Drink>> {
            override fun onResponse(call: Call<List<Drink>>, response: Response<List<Drink>>) {
                if (response.isSuccessful) {
                    drinks = response.body() ?: emptyList()
                    displayDrinks(drinks)
                } else {
                    Log.e(TAG, "Failed to fetch drinks: ${response.code()}")
                }
            }

            override fun onFailure(call: Call<List<Drink>>, t: Throwable) {
                Log.e(TAG, "Failed to fetch drinks", t)
            }
        })
    }

    private fun displayDrinks(drinks: List<Drink>) {
        val adapter = DrinkAdapter(drinks)
        gridView.adapter = adapter // 设置 GridView 的适配器
    }

    private fun showDrinkDetails(drink: Drink) {
        val intent = Intent(this, DrinkDetailsActivity::class.java)
        intent.putExtra(DrinkDetailsActivity.EXTRA_DRINK, drink)
        startActivity(intent)
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        if (item.itemId == android.R.id.home) {
            onBackPressed()
            return true
        }
        return super.onOptionsItemSelected(item)
    }

    companion object {
        private const val TAG = "BrowseDrinksActivity"
    }
}

注意:在 displayDrinks 方法中,我已经设置了 GridView 的适配器,这样才能确保动态填充的数据与 GridView 相关联。希望这能解决您的问题。

英文:

How to set an on item click event listener for a grid view that is dynamically being populated?

I have set the click listener for the gridView items. They are clickable in the xml file. However the click action is not triggered. I have tried to set the onclick listener in the onCreate method and also in the display drinks method. None of that worked. using setOnClickListener is giving the same result.

It seems like the click listener might not be properly attached or initialized. Is there a specific place or method where I should set the listener to ensure that it's working correctly? Maybe the issue lies in the fact that the GridView is being dynamically populated. Could that be causing the problem?

How can I solve this issue?

class DrinkAdapter(private val drinks: List&lt;Drink&gt;) : BaseAdapter() {
override fun getCount(): Int {
return drinks.size
}
override fun getItem(position: Int): Any {
return drinks[position]
}
override fun getItemId(position: Int): Long {
return position.toLong()
}
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
val view = convertView ?: LayoutInflater.from(parent?.context)
.inflate(R.layout.grid_item_drink, parent, false)
val drink = drinks[position]
val imageView = view.findViewById&lt;ImageView&gt;(R.id.drinkImage)
val textView = view.findViewById&lt;TextView&gt;(R.id.drinkName)
imageView.viewTreeObserver.addOnGlobalLayoutListener {
val width = imageView.width
val height = imageView.height
GlideApp.with(imageView)
.load(drink.getImageUrl())
.override(width, height)
.placeholder(R.drawable.placeholder_image)
.error(R.drawable.error_image)
.into(imageView)
}
textView.text = drink.name
return view
}
}
class BrowseDrinksActivity : AppCompatActivity() {
private lateinit var gridView: GridView
private lateinit var drinks: List&lt;Drink&gt;
private val apiService: BrowseApiService by lazy {
Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(BrowseApiService::class.java)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.browse_drinks)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
gridView = findViewById(R.id.gridView)
gridView.onItemClickListener =
AdapterView.OnItemClickListener { _, _, position, _ -&gt;
val drink = drinks[position]
showDrinkDetails(drink)
}
fetchDrinks()
}
private fun fetchDrinks() {
val call: Call&lt;List&lt;Drink&gt;&gt; = apiService.getDrinks()
call.enqueue(object : Callback&lt;List&lt;Drink&gt;&gt; {
override fun onResponse(call: Call&lt;List&lt;Drink&gt;&gt;, response: Response&lt;List&lt;Drink&gt;&gt;) {
if (response.isSuccessful) {
drinks = response.body() ?: emptyList()
displayDrinks(drinks)
} else {
Log.e(TAG, &quot;Failed to fetch drinks: ${response.code()}&quot;)
}
}
override fun onFailure(call: Call&lt;List&lt;Drink&gt;&gt;, t: Throwable) {
Log.e(TAG, &quot;Failed to fetch drinks&quot;, t)
}
})
}
private fun displayDrinks(drinks: List&lt;Drink&gt;) {
val adapter = DrinkAdapter(drinks)
}
private fun showDrinkDetails(drink: Drink) {
val intent = Intent(this, DrinkDetailsActivity::class.java)
intent.putExtra(DrinkDetailsActivity.EXTRA_DRINK, drink)
startActivity(intent)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (item.itemId == android.R.id.home) {
onBackPressed()
return true
}
return super.onOptionsItemSelected(item)
}
companion object {
private const val TAG = &quot;BrowseDrinksActivity&quot;
}
}

答案1

得分: 1

尝试创建一个单独的接口,比如:

interface DrinkListeners {
    fun onDrinkClicked(drink: Drink)
}

在以下方式中更改DrinkAdapter的构造函数:

class DrinkAdapter(private val drinks: List<Drink>, private val listeners: DrinkListeners) : BaseAdapter()

现在,每当发生点击事件时,例如:

imageView.setOnClickListener {
    listeners.onDrinkClicked(drinks[position])
}

更改类的签名:

class BrowseDrinksActivity : AppCompatActivity(), DrinkListeners

最后,在同一类中覆盖函数:

override fun onDrinkClicked(drink: Drink) {
    TODO("Not yet implemented")
}
英文:

Try creating a separate interface let's say

interface DrinkListeners {
fun onDrinkClicked(drink: Drink)
}

Change the constructor of the DrinkAdapter in the following manner:

class DrinkAdapter(private val drinks: List&lt;Drink&gt;, private val listeners: DrinkListeners) : BaseAdapter()

Now use this listeners whenever a click happens say for example:

imageView.setOnClickListener {
listeners.onDrinkClicked(drinks[position])
}

Change the class signature

class BrowseDrinksActivity : AppCompatActivity(), DrinkListeners

Finally in the same class override the function:

 override fun onDrinkClicked(drink: Drink) {
TODO(&quot;Not yet implemented&quot;)
}

huangapple
  • 本文由 发表于 2023年5月28日 19:48:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/76351325.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定