英文:
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<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)
}
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"
}
}
答案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<Drink>, 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("Not yet implemented")
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论