如何在片段中使用包含 TextView 数组的 RecyclerView?

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

How do I use RecyclerView with an array of TextViews inside a fragment?

问题

我理解你的请求,以下是你提供的代码的翻译:

MainActivity.kt - 我尝试使用Android Studio的底部选项卡导航器自动生成以下代码:

  1. package com.example.bbar
  2. import android.os.Bundle
  3. import com.google.android.material.bottomnavigation.BottomNavigationView
  4. import androidx.appcompat.app.AppCompatActivity
  5. import androidx.navigation.findNavController
  6. import androidx.navigation.ui.AppBarConfiguration
  7. import androidx.navigation.ui.setupActionBarWithNavController
  8. import androidx.navigation.ui.setupWithNavController
  9. import com.example.bbar.databinding.ActivityMainBinding
  10. class MainActivity : AppCompatActivity() {
  11. private lateinit var binding: ActivityMainBinding
  12. override fun onCreate(savedInstanceState: Bundle?) {
  13. super.onCreate(savedInstanceState)
  14. binding = ActivityMainBinding.inflate(layoutInflater)
  15. setContentView(binding.root)
  16. val navView: BottomNavigationView = binding.navView
  17. val navController = findNavController(R.id.nav_host_fragment_activity_main)
  18. // 由于每个菜单都应被视为顶级目标,因此将每个菜单ID作为一组ID传递。
  19. val appBarConfiguration = AppBarConfiguration(
  20. setOf(
  21. R.id.navigation_home, R.id.navigation_dashboard, R.id.navigation_notifications
  22. )
  23. )
  24. setupActionBarWithNavController(navController, appBarConfiguration)
  25. navView.setupWithNavController(navController)
  26. }
  27. }

HomeFragment.kt

  1. package com.example.bbar.ui.home
  2. import android.os.Bundle
  3. import android.view.LayoutInflater
  4. import android.view.View
  5. import android.view.ViewGroup
  6. import androidx.fragment.app.Fragment
  7. import androidx.recyclerview.widget.LinearLayoutManager
  8. import com.example.bbar.R
  9. import com.example.bbar.databinding.FragmentHomeBinding
  10. class HomeFragment : Fragment() {
  11. private var _binding: FragmentHomeBinding? = null
  12. private val binding get() = _binding!!
  13. private lateinit var foodlistadapter: Foodlistadapter
  14. override fun onCreateView(
  15. inflater: LayoutInflater, container: ViewGroup?,
  16. savedInstanceState: Bundle?
  17. ): View {
  18. _binding = FragmentHomeBinding.inflate(inflater, container, false)
  19. return inflater.inflate(R.layout.fragment_home, container, false)
  20. }
  21. override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
  22. super.onViewCreated(view, savedInstanceState)
  23. foodlistadapter = Foodlistadapter(mutableListOf())
  24. binding.rvFoodItems.adapter = foodlistadapter
  25. binding.rvFoodItems.layoutManager = LinearLayoutManager(activity)
  26. binding.bSubmit.setOnClickListener{
  27. val foodTitle= binding.etName.text.toString()
  28. if (foodTitle.isNotEmpty()){
  29. val food= food(foodTitle, binding.etCalories.text.toString().toInt(), false )
  30. foodlistadapter.addFood(food)
  31. binding.etName.text.clear()
  32. binding.etCalories.text.clear()
  33. }
  34. }
  35. binding.bDelete.setOnClickListener{
  36. foodlistadapter.deleteFood()
  37. }
  38. }
  39. override fun onDestroy() {
  40. super.onDestroy()
  41. _binding = null
  42. }
  43. }

foodlistadapter.kt

  1. package com.example.bbar.ui.home
  2. import android.annotation.SuppressLint
  3. import android.view.LayoutInflater
  4. import android.view.View
  5. import android.view.ViewGroup
  6. import androidx.recyclerview.widget.RecyclerView
  7. import com.example.bbar.R
  8. import android.graphics.Paint.STRIKE_THRU_TEXT_FLAG
  9. import android.widget.TextView
  10. import com.example.bbar.databinding.FooditemBinding
  11. @SuppressLint("StaticFieldLeak")
  12. private var _binding: FooditemBinding? = null
  13. private val binding get() = _binding!!
  14. class Foodlistadapter(
  15. private val foods: MutableList<food>
  16. ) : RecyclerView.Adapter<Foodlistadapter.foodlistviewholder>() {
  17. class foodlistviewholder(itemView: View) : RecyclerView.ViewHolder(itemView)
  18. override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): foodlistviewholder {
  19. return foodlistviewholder(
  20. LayoutInflater.from(parent.context).inflate(
  21. R.layout.fragment_home,
  22. parent,
  23. false
  24. )
  25. )
  26. }
  27. fun addFood(food: food) {
  28. foods.add(food)
  29. notifyItemInserted(foods.size - 1)
  30. }
  31. fun deleteFood() {
  32. foods.removeAll { foods -> foods.isChecked }
  33. notifyDataSetChanged()
  34. }
  35. private fun toggleStrikeThrough(tvFood: TextView, isChecked: Boolean) {
  36. if (isChecked) {
  37. tvFood.paintFlags = tvFood.paintFlags or STRIKE_THRU_TEXT_FLAG
  38. } else {
  39. tvFood.paintFlags = tvFood.paintFlags or STRIKE_THRU_TEXT_FLAG.inv()
  40. }
  41. }
  42. override fun onBindViewHolder(holder: foodlistviewholder, position: Int) {
  43. val currentFood = foods[position]
  44. holder.itemView.apply {
  45. binding.tvFood.text = currentFood.name
  46. binding.tvCalories.text= currentFood.calories.toString()
  47. binding.cbDelete.isChecked = currentFood.isChecked
  48. toggleStrikeThrough(binding.tvFood, currentFood.isChecked)
  49. binding.cbDelete.setOnCheckedChangeListener { _, isChecked ->
  50. toggleStrikeThrough(binding.tvFood, isChecked)
  51. currentFood.isChecked = !currentFood.isChecked
  52. }
  53. }
  54. }
  55. override fun getItemCount(): Int {
  56. return foods.size
  57. }
  58. }

food.kt

  1. package com.example.bbar.ui.home
  2. data class food (
  3. val name : String,
  4. val calories: Int,
  5. var isChecked: Boolean,
  6. )

希望这可以帮助你解决问题。如果你有任何其他问题,请随时提出。

英文:

I am new to Kotlin and started coding a few years ago. I am trying to make a calorie counter application, but I am stuck at adding the food and calories in the first place. I think the issue is that I incorrectly syntaxed the code somewhere and/or logic errors that I don't yet understand in this language.

The code/application runs, it just doesn't pass the values to the recyclerview's textview when I press the "add" button, and doesn't clear the EditText components. For some reason the button's setOnClickListener (in HomeFragment.kt under onViewCreated) does not work.

MainActivity.kt - I tried out Android Studio's auto generator to use BottomTabNavigator

  1. package com.example.bbar
  2. import android.os.Bundle
  3. import com.google.android.material.bottomnavigation.BottomNavigationView
  4. import androidx.appcompat.app.AppCompatActivity
  5. import androidx.navigation.findNavController
  6. import androidx.navigation.ui.AppBarConfiguration
  7. import androidx.navigation.ui.setupActionBarWithNavController
  8. import androidx.navigation.ui.setupWithNavController
  9. import com.example.bbar.databinding.ActivityMainBinding
  10. class MainActivity : AppCompatActivity() {
  11. private lateinit var binding: ActivityMainBinding
  12. override fun onCreate(savedInstanceState: Bundle?) {
  13. super.onCreate(savedInstanceState)
  14. binding = ActivityMainBinding.inflate(layoutInflater)
  15. setContentView(binding.root)
  16. val navView: BottomNavigationView = binding.navView
  17. val navController = findNavController(R.id.nav_host_fragment_activity_main)
  18. // Passing each menu ID as a set of Ids because each
  19. // menu should be considered as top level destinations.
  20. val appBarConfiguration = AppBarConfiguration(
  21. setOf(
  22. R.id.navigation_home, R.id.navigation_dashboard, R.id.navigation_notifications
  23. )
  24. )
  25. setupActionBarWithNavController(navController, appBarConfiguration)
  26. navView.setupWithNavController(navController)
  27. }
  28. }

HomeFragment.kt

  1. package com.example.bbar.ui.home
  2. import android.os.Bundle
  3. import android.view.LayoutInflater
  4. import android.view.View
  5. import android.view.ViewGroup
  6. import androidx.fragment.app.Fragment
  7. import androidx.recyclerview.widget.LinearLayoutManager
  8. import com.example.bbar.R
  9. import com.example.bbar.databinding.FragmentHomeBinding
  10. class HomeFragment : Fragment() {
  11. private var _binding: FragmentHomeBinding? = null
  12. private val binding get() = _binding!!
  13. private lateinit var foodlistadapter: Foodlistadapter
  14. override fun onCreateView(
  15. inflater: LayoutInflater, container: ViewGroup?,
  16. savedInstanceState: Bundle?
  17. ): View {
  18. _binding = FragmentHomeBinding.inflate(inflater, container, false)
  19. return inflater.inflate(R.layout.fragment_home, container, false)
  20. }
  21. override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
  22. super.onViewCreated(view, savedInstanceState)
  23. foodlistadapter = Foodlistadapter(mutableListOf())
  24. binding.rvFoodItems.adapter = foodlistadapter
  25. binding.rvFoodItems.layoutManager = LinearLayoutManager(activity)
  26. binding.bSubmit.setOnClickListener{
  27. val foodTitle= binding.etName.text.toString()
  28. if (foodTitle.isNotEmpty()){
  29. val food= food(foodTitle, binding.etCalories.text.toString().toInt(), false )
  30. foodlistadapter.addFood(food)
  31. binding.etName.text.clear()
  32. binding.etCalories.text.clear()
  33. }
  34. }
  35. binding.bDelete.setOnClickListener{
  36. foodlistadapter.deleteFood()
  37. }
  38. }
  39. override fun onDestroy() {
  40. super.onDestroy()
  41. _binding = null
  42. }
  43. }

foodlistadapter.kt

  1. package com.example.bbar.ui.home
  2. import android.annotation.SuppressLint
  3. import android.view.LayoutInflater
  4. import android.view.View
  5. import android.view.ViewGroup
  6. import androidx.recyclerview.widget.RecyclerView
  7. import com.example.bbar.R
  8. import android.graphics.Paint.STRIKE_THRU_TEXT_FLAG
  9. import android.widget.TextView
  10. import com.example.bbar.databinding.FooditemBinding
  11. @SuppressLint(&quot;StaticFieldLeak&quot;)
  12. private var _binding: FooditemBinding? = null
  13. private val binding get() = _binding!!
  14. class Foodlistadapter(
  15. private val foods: MutableList&lt;food&gt;
  16. ) : RecyclerView.Adapter&lt;Foodlistadapter.foodlistviewholder&gt;() {
  17. class foodlistviewholder(itemView: View) : RecyclerView.ViewHolder(itemView)
  18. override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): foodlistviewholder {
  19. return foodlistviewholder(
  20. LayoutInflater.from(parent.context).inflate(
  21. R.layout.fragment_home,
  22. parent,
  23. false
  24. )
  25. )
  26. }
  27. fun addFood(food: food) {
  28. foods.add(food)
  29. notifyItemInserted(foods.size - 1)
  30. }
  31. fun deleteFood() {
  32. foods.removeAll { foods -&gt; foods.isChecked }
  33. notifyDataSetChanged()
  34. }
  35. private fun toggleStrikeThrough(tvFood: TextView, isChecked: Boolean) {
  36. if (isChecked) {
  37. tvFood.paintFlags = tvFood.paintFlags or STRIKE_THRU_TEXT_FLAG
  38. } else {
  39. tvFood.paintFlags = tvFood.paintFlags or STRIKE_THRU_TEXT_FLAG.inv()
  40. }
  41. }
  42. override fun onBindViewHolder(holder: foodlistviewholder, position: Int) {
  43. val currentFood = foods[position]
  44. holder.itemView.apply {
  45. binding.tvFood.text = currentFood.name
  46. binding.tvCalories.text= currentFood.calories.toString()
  47. binding.cbDelete.isChecked = currentFood.isChecked
  48. toggleStrikeThrough(binding.tvFood, currentFood.isChecked)
  49. binding.cbDelete.setOnCheckedChangeListener { _, isChecked -&gt;
  50. toggleStrikeThrough(binding.tvFood, isChecked)
  51. currentFood.isChecked = !currentFood.isChecked
  52. }
  53. }
  54. }
  55. override fun getItemCount(): Int {
  56. return foods.size
  57. }
  58. }

food.kt

  1. package com.example.bbar.ui.home
  2. data class food (
  3. val name : String,
  4. val calories: Int,
  5. var isChecked: Boolean,
  6. )

Sorry for the length of this post, just trying to include everything that could help.

Disclaimer: I am only asking for you to help me solve this specific issue, I understand that there are still many things for me to learn so I also would appreciate if you could kindly explain some things I did wrong.

Tried to give different parameters to LinearLayoutManager in HomeFragment.kt to see if the issue is there.

答案1

得分: 0

问题出在你的Fragment的onCreateView方法上。
你重复两次膨胀了你的视图,而在分配给它充气后没有使用绑定。

简而言之,

  1. 通过FragmentHomeBinding.inflate充气一个视图,并将绑定分配给它。
  2. 没有使用该充气的视图,而是通过inflater.inflate(...)再次充气了一个新视图,并使用这个新视图。

简单地使用:

  1. override fun onCreateView(
  2. inflater: LayoutInflater, container: ViewGroup?,
  3. savedInstanceState: Bundle?
  4. ): View {
  5. _binding = FragmentHomeBinding.inflate(inflater, container, false)
  6. return binding!!.root
  7. }
英文:

The problem is your Fragment's onCreateView.
You are inflating your view twice & not using the binding after assigning it a inflated view.

In short,

  1. You are inflating a view via FragmentHomeBinding.inflate, assigning the binding to it.
  2. Not using that inflated view but inflating another via inflater.inflate(...) & using this new view.

Simply use:

  1. override fun onCreateView(
  2. inflater: LayoutInflater, container: ViewGroup?,
  3. savedInstanceState: Bundle?
  4. ): View {
  5. _binding = FragmentHomeBinding.inflate(inflater, container, false)
  6. return binding!!.root
  7. }

huangapple
  • 本文由 发表于 2023年6月18日 17:30:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/76499862.html
匿名

发表评论

匿名网友

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

确定