我正在编写一个简单的项目来可视化笑话列表。当我尝试将所有内容包装在片段中时,遇到了一个问题:元素停止绘制,我发现问题出在ListAdapter中。 onCreateViewHolder方法没有被调用,onBindViewHolder也是如此。使用 ContainerView 进行标记:
<?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:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.MainActivity" >
<androidx.fragment.app.FragmentContainerView
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:defaultNavHost="true"
app:navGraph="@navigation/nav_graph"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
片段标记:
<?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:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/purple_100"
android:paddingHorizontal="20dp"
android:paddingVertical="6dp"
tools:context=".ui.main.ListFragment">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:listitem="@layout/joke_item" />
</androidx.constraintlayout.widget.ConstraintLayout>
片段代码:
class ListFragment : Fragment(R.layout.fragment_list) {
private lateinit var binding: FragmentListBinding
private lateinit var viewModel: JokesListViewModel
private val adapter = JokesListAdapter {
findNavController().navigate(
ListFragmentDirections.actionListFragmentToJokeDetailsFragment(
viewModel.getJokeId(it)
)
)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
initViewModel()
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding = FragmentListBinding.inflate(layoutInflater)
binding.recyclerView.adapter = adapter
binding.recyclerView.layoutManager = LinearLayoutManager(activity)
savedInstanceState ?: run {
viewModel.generateJokes()
}
}
private fun initViewModel() {
val factory = JokeViewModelFactory(JokesGenerator)
viewModel = ViewModelProvider(this, factory)[JokesListViewModel::class.java]
viewModel.jokes.observe(this) {
adapter.submitList(it)
Toast.makeText(activity, "jokes updated", Toast.LENGTH_SHORT).show()
}
viewModel.error.observe(this) {
Toast.makeText(activity, it, Toast.LENGTH_SHORT).show()
}
}
}
适配器代码:
class JokesListAdapter(
private val clickListener: (Int) -> Unit
) :
ListAdapter<Joke, JokesViewHolder>(JokeItemCallback) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): JokesViewHolder {
val inflater = LayoutInflater.from(parent.context)
val binding = JokeItemBinding.inflate(inflater, parent, false)
return JokesViewHolder(binding).apply {
binding.root.setOnClickListener {
handlePersonClick(bindingAdapterPosition)
}
}
}
override fun getItemCount() = currentList.size
override fun onBindViewHolder(holder: JokesViewHolder, position: Int) {
holder.bind(currentList[position])
}
private fun handlePersonClick(position: Int) {
if (position != RecyclerView.NO_POSITION) {
clickListener(position)
}
}
}
和视图持有者:
class JokesViewHolder(private val binding: JokeItemBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind(joke: Joke) {
binding.textViewQuestion.text = joke.jokeQuestion
binding.textViewAnswer.text = joke.jokeAnswer
binding.textViewCategory.text = joke.category
println("!!! $joke.id binded")
}
}
此行创建与片段无关的视图副本,它不会显示在屏幕上,因此不使用适配器。
相反,您应该获取与片段创建的视图的绑定(它作为方法参数):
您需要更改 onViewCreated 方法并重写 onCreateView 方法,如下所示: