我正在尝试使用 recyclerview 在屏幕上打印列表,但适配器部分的代码无法正常工作
I'm trying to print a list on the screen using the recyclerview, but the code in the adapter part is not working
MainActivity如下。
屏幕上什么也没有,但我不知道是哪一部分出了问题。
如何添加 TV_item_name 的值?
并且在日志中,它来自内部 class 的 DetailViewAdapter。
Log.d (logTag,onCreateViewHolder11iscaled") 值也没有输出,请问是什么问题?
package com.example.test_recyclerview
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.cardview.widget.CardView
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.test_recyclerview.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
private lateinit var binding : ActivityMainBinding
var logTag : String? = "로그 MainActivity"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
Log.d(logTag,"111 onCreate is called")
binding.mRecyclerView.layoutManager = LinearLayoutManager(this)
val adapter = DetailViewAdapter()
Log.d(logTag,"222 onCreate is called")
binding.mRecyclerView.adapter = adapter
}
override fun onDestroy() {
super.onDestroy()
binding.mRecyclerView.adapter = null
}
inner class DetailViewAdapter : RecyclerView.Adapter<DetailViewAdapter.ViewHolder>() {
private var list = ArrayList<String>()
var logTag : String? = "로그 MainActivity"
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DetailViewAdapter.ViewHolder {
Log.d(logTag,"onCreateViewHolder11 is called")
list = getItemList()
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_custom_row, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
Log.d(logTag,"onBindViewHolder is called")
for (i in 1 until list.size) {
Log.d(logTag,"onBindViewHolder is called // list[$i] =" + list[i])
holder.tvItem.text = list[i]
}
}
override fun getItemCount(): Int {
return list.size
}
private fun getItemList(): ArrayList<String> {
for (i in 1..8) {
list.add(i, "Item $i")
}
return list
}
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val tvItem : TextView = view.findViewById(R.id.tv_item_name)
val cardViewItem : CardView = view.findViewById(R.id.card_view_item)
}
}
}
item_custom_row.xml
<?xml version="1.0" encoding="utf-8"?>
`enter code here`<LinearLayout 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="match_parent"
android:layout_height="wrap_content">
<androidx.cardview.widget.CardView
android:id="@+id/card_view_item"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:padding="10dp"
app:cardCornerRadius="5dp"
app:cardElevation="3dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal"
tools:ignore="UseCompoundDrawables">
<ImageView
android:layout_width="50dp"
android:layout_height="50dp"
android:contentDescription="@string/app_name"
android:src="@mipmap/ic_launcher" />
<TextView
android:id="@+id/tv_item_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:textColor="@android:color/black"
android:textSize="18sp"
android:textStyle="bold"
tools:text="Item" />
</LinearLayout>
</androidx.cardview.widget.CardView>
</LinearLayout>
activity_main.xml
<?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="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/m_RecyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
从您发布的代码中我可以看出您的代码有两个问题。
第一个是您试图从视图持有者内部填充数据列表。发生的情况如下:
- 适配器已创建
- 适配器想知道它应该创建多少个视图持有者以查看如何填充回收器视图。
- 适配器调用 getItemCount 并且此方法 returns 0,因为列表尚未填充。
- 不会调用任何其他内容,因为无需执行任何其他内容。
因此,要解决此问题,最简单的方法是使 getItemCount return 8 就可以了。但是,解决此问题的更好方法是在适配器外部实例化列表,例如在 activity 中,并在初始化适配器时将其作为构造函数参数传递。
我看到的第二个问题是 onBindViewHolder 方法。您正在遍历列表以设置文本,这将导致对于所有项目,您只会将文本设置为最后一项(第 8 项)。您需要记住 onBindViewHolder 是一种在视图持有者需要刷新其内容时调用的方法,因为它将用于显示列表的不同项目,这就是为什么将位置作为参数传递给该方法的原因,因此您可以做类似的事情:
holder.tvItem.text = list[position]
** 作为第二个问题的旁注,我看到并用于呈现视图持有者内容的更通用的方法是创建一个名为“bind”的 public 方法,它是传递需要渲染的项目,在视图持有者上,您将拥有如何绘制它的逻辑。类似于:
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(list[position])
}
/// Inside the view holder
fun bind(item: String) {
tvItem.text = item
}
问题是您在 onCreateViewHolder
中分配列表,但不会被调用,因为您的 list.size
返回 0。
在此
中正确指出
- 在适配器外部创建列表并从构造函数传递它
- 更改
onBindViewHolder
中的实施
以下是您的用例的完整示例:
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
var logTag: String? = "로그 MainActivity"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
Log.d(logTag, "111 onCreate is called")
binding.mRecyclerView.layoutManager = LinearLayoutManager(this)
val adapter = DetailViewAdapter(getItemList())
Log.d(logTag, "222 onCreate is called")
binding.mRecyclerView.adapter = adapter
}
private fun getItemList(): ArrayList<String> {
val list = ArrayList<String>()
for (i in 1..8) {
list.add("Item $i")
}
return list
}
override fun onDestroy() {
super.onDestroy()
binding.mRecyclerView.adapter = null
}
inner class DetailViewAdapter(private val list: ArrayList<String>) :
RecyclerView.Adapter<DetailViewAdapter.ViewHolder>() {
var logTag: String? = "로그 MainActivity"
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): DetailViewAdapter.ViewHolder {
Log.d(logTag, "onCreateViewHolder11 is called")
val view =
LayoutInflater.from(parent.context).inflate(R.layout.item_custom_row, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
Log.d(logTag, "onBindViewHolder is called")
holder.tvItem.text = list[position]
}
override fun getItemCount(): Int {
return list.size
}
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val tvItem: TextView = view.findViewById(R.id.tv_item_name)
val cardViewItem: CardView = view.findViewById(R.id.card_view_item)
}
}
}
MainActivity如下。 屏幕上什么也没有,但我不知道是哪一部分出了问题。 如何添加 TV_item_name 的值?
并且在日志中,它来自内部 class 的 DetailViewAdapter。 Log.d (logTag,onCreateViewHolder11iscaled") 值也没有输出,请问是什么问题?
package com.example.test_recyclerview
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.cardview.widget.CardView
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.test_recyclerview.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
private lateinit var binding : ActivityMainBinding
var logTag : String? = "로그 MainActivity"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
Log.d(logTag,"111 onCreate is called")
binding.mRecyclerView.layoutManager = LinearLayoutManager(this)
val adapter = DetailViewAdapter()
Log.d(logTag,"222 onCreate is called")
binding.mRecyclerView.adapter = adapter
}
override fun onDestroy() {
super.onDestroy()
binding.mRecyclerView.adapter = null
}
inner class DetailViewAdapter : RecyclerView.Adapter<DetailViewAdapter.ViewHolder>() {
private var list = ArrayList<String>()
var logTag : String? = "로그 MainActivity"
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DetailViewAdapter.ViewHolder {
Log.d(logTag,"onCreateViewHolder11 is called")
list = getItemList()
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_custom_row, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
Log.d(logTag,"onBindViewHolder is called")
for (i in 1 until list.size) {
Log.d(logTag,"onBindViewHolder is called // list[$i] =" + list[i])
holder.tvItem.text = list[i]
}
}
override fun getItemCount(): Int {
return list.size
}
private fun getItemList(): ArrayList<String> {
for (i in 1..8) {
list.add(i, "Item $i")
}
return list
}
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val tvItem : TextView = view.findViewById(R.id.tv_item_name)
val cardViewItem : CardView = view.findViewById(R.id.card_view_item)
}
}
}
item_custom_row.xml
<?xml version="1.0" encoding="utf-8"?>
`enter code here`<LinearLayout 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="match_parent"
android:layout_height="wrap_content">
<androidx.cardview.widget.CardView
android:id="@+id/card_view_item"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:padding="10dp"
app:cardCornerRadius="5dp"
app:cardElevation="3dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal"
tools:ignore="UseCompoundDrawables">
<ImageView
android:layout_width="50dp"
android:layout_height="50dp"
android:contentDescription="@string/app_name"
android:src="@mipmap/ic_launcher" />
<TextView
android:id="@+id/tv_item_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:textColor="@android:color/black"
android:textSize="18sp"
android:textStyle="bold"
tools:text="Item" />
</LinearLayout>
</androidx.cardview.widget.CardView>
</LinearLayout>
activity_main.xml
<?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="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/m_RecyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
从您发布的代码中我可以看出您的代码有两个问题。
第一个是您试图从视图持有者内部填充数据列表。发生的情况如下:
- 适配器已创建
- 适配器想知道它应该创建多少个视图持有者以查看如何填充回收器视图。
- 适配器调用 getItemCount 并且此方法 returns 0,因为列表尚未填充。
- 不会调用任何其他内容,因为无需执行任何其他内容。
因此,要解决此问题,最简单的方法是使 getItemCount return 8 就可以了。但是,解决此问题的更好方法是在适配器外部实例化列表,例如在 activity 中,并在初始化适配器时将其作为构造函数参数传递。
我看到的第二个问题是 onBindViewHolder 方法。您正在遍历列表以设置文本,这将导致对于所有项目,您只会将文本设置为最后一项(第 8 项)。您需要记住 onBindViewHolder 是一种在视图持有者需要刷新其内容时调用的方法,因为它将用于显示列表的不同项目,这就是为什么将位置作为参数传递给该方法的原因,因此您可以做类似的事情:
holder.tvItem.text = list[position]
** 作为第二个问题的旁注,我看到并用于呈现视图持有者内容的更通用的方法是创建一个名为“bind”的 public 方法,它是传递需要渲染的项目,在视图持有者上,您将拥有如何绘制它的逻辑。类似于:
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(list[position])
}
/// Inside the view holder
fun bind(item: String) {
tvItem.text = item
}
问题是您在 onCreateViewHolder
中分配列表,但不会被调用,因为您的 list.size
返回 0。
在此
- 在适配器外部创建列表并从构造函数传递它
- 更改
onBindViewHolder
中的实施
以下是您的用例的完整示例:
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
var logTag: String? = "로그 MainActivity"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
Log.d(logTag, "111 onCreate is called")
binding.mRecyclerView.layoutManager = LinearLayoutManager(this)
val adapter = DetailViewAdapter(getItemList())
Log.d(logTag, "222 onCreate is called")
binding.mRecyclerView.adapter = adapter
}
private fun getItemList(): ArrayList<String> {
val list = ArrayList<String>()
for (i in 1..8) {
list.add("Item $i")
}
return list
}
override fun onDestroy() {
super.onDestroy()
binding.mRecyclerView.adapter = null
}
inner class DetailViewAdapter(private val list: ArrayList<String>) :
RecyclerView.Adapter<DetailViewAdapter.ViewHolder>() {
var logTag: String? = "로그 MainActivity"
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): DetailViewAdapter.ViewHolder {
Log.d(logTag, "onCreateViewHolder11 is called")
val view =
LayoutInflater.from(parent.context).inflate(R.layout.item_custom_row, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
Log.d(logTag, "onBindViewHolder is called")
holder.tvItem.text = list[position]
}
override fun getItemCount(): Int {
return list.size
}
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val tvItem: TextView = view.findViewById(R.id.tv_item_name)
val cardViewItem: CardView = view.findViewById(R.id.card_view_item)
}
}
}