英文:
How do I use RecyclerView with an array of TextViews inside a fragment?
问题
我理解你的请求,以下是你提供的代码的翻译:
MainActivity.kt - 我尝试使用Android Studio的底部选项卡导航器自动生成以下代码:
package com.example.bbar
import android.os.Bundle
import com.google.android.material.bottomnavigation.BottomNavigationView
import androidx.appcompat.app.AppCompatActivity
import androidx.navigation.findNavController
import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.setupActionBarWithNavController
import androidx.navigation.ui.setupWithNavController
import com.example.bbar.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
val navView: BottomNavigationView = binding.navView
val navController = findNavController(R.id.nav_host_fragment_activity_main)
// 由于每个菜单都应被视为顶级目标,因此将每个菜单ID作为一组ID传递。
val appBarConfiguration = AppBarConfiguration(
setOf(
R.id.navigation_home, R.id.navigation_dashboard, R.id.navigation_notifications
)
)
setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController)
}
}
HomeFragment.kt
package com.example.bbar.ui.home
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.bbar.R
import com.example.bbar.databinding.FragmentHomeBinding
class HomeFragment : Fragment() {
private var _binding: FragmentHomeBinding? = null
private val binding get() = _binding!!
private lateinit var foodlistadapter: Foodlistadapter
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentHomeBinding.inflate(inflater, container, false)
return inflater.inflate(R.layout.fragment_home, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
foodlistadapter = Foodlistadapter(mutableListOf())
binding.rvFoodItems.adapter = foodlistadapter
binding.rvFoodItems.layoutManager = LinearLayoutManager(activity)
binding.bSubmit.setOnClickListener{
val foodTitle= binding.etName.text.toString()
if (foodTitle.isNotEmpty()){
val food= food(foodTitle, binding.etCalories.text.toString().toInt(), false )
foodlistadapter.addFood(food)
binding.etName.text.clear()
binding.etCalories.text.clear()
}
}
binding.bDelete.setOnClickListener{
foodlistadapter.deleteFood()
}
}
override fun onDestroy() {
super.onDestroy()
_binding = null
}
}
foodlistadapter.kt
package com.example.bbar.ui.home
import android.annotation.SuppressLint
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.example.bbar.R
import android.graphics.Paint.STRIKE_THRU_TEXT_FLAG
import android.widget.TextView
import com.example.bbar.databinding.FooditemBinding
@SuppressLint("StaticFieldLeak")
private var _binding: FooditemBinding? = null
private val binding get() = _binding!!
class Foodlistadapter(
private val foods: MutableList<food>
) : RecyclerView.Adapter<Foodlistadapter.foodlistviewholder>() {
class foodlistviewholder(itemView: View) : RecyclerView.ViewHolder(itemView)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): foodlistviewholder {
return foodlistviewholder(
LayoutInflater.from(parent.context).inflate(
R.layout.fragment_home,
parent,
false
)
)
}
fun addFood(food: food) {
foods.add(food)
notifyItemInserted(foods.size - 1)
}
fun deleteFood() {
foods.removeAll { foods -> foods.isChecked }
notifyDataSetChanged()
}
private fun toggleStrikeThrough(tvFood: TextView, isChecked: Boolean) {
if (isChecked) {
tvFood.paintFlags = tvFood.paintFlags or STRIKE_THRU_TEXT_FLAG
} else {
tvFood.paintFlags = tvFood.paintFlags or STRIKE_THRU_TEXT_FLAG.inv()
}
}
override fun onBindViewHolder(holder: foodlistviewholder, position: Int) {
val currentFood = foods[position]
holder.itemView.apply {
binding.tvFood.text = currentFood.name
binding.tvCalories.text= currentFood.calories.toString()
binding.cbDelete.isChecked = currentFood.isChecked
toggleStrikeThrough(binding.tvFood, currentFood.isChecked)
binding.cbDelete.setOnCheckedChangeListener { _, isChecked ->
toggleStrikeThrough(binding.tvFood, isChecked)
currentFood.isChecked = !currentFood.isChecked
}
}
}
override fun getItemCount(): Int {
return foods.size
}
}
food.kt
package com.example.bbar.ui.home
data class food (
val name : String,
val calories: Int,
var isChecked: Boolean,
)
希望这可以帮助你解决问题。如果你有任何其他问题,请随时提出。
英文:
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
package com.example.bbar
import android.os.Bundle
import com.google.android.material.bottomnavigation.BottomNavigationView
import androidx.appcompat.app.AppCompatActivity
import androidx.navigation.findNavController
import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.setupActionBarWithNavController
import androidx.navigation.ui.setupWithNavController
import com.example.bbar.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
val navView: BottomNavigationView = binding.navView
val navController = findNavController(R.id.nav_host_fragment_activity_main)
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
val appBarConfiguration = AppBarConfiguration(
setOf(
R.id.navigation_home, R.id.navigation_dashboard, R.id.navigation_notifications
)
)
setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController)
}
}
HomeFragment.kt
package com.example.bbar.ui.home
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.bbar.R
import com.example.bbar.databinding.FragmentHomeBinding
class HomeFragment : Fragment() {
private var _binding: FragmentHomeBinding? = null
private val binding get() = _binding!!
private lateinit var foodlistadapter: Foodlistadapter
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentHomeBinding.inflate(inflater, container, false)
return inflater.inflate(R.layout.fragment_home, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
foodlistadapter = Foodlistadapter(mutableListOf())
binding.rvFoodItems.adapter = foodlistadapter
binding.rvFoodItems.layoutManager = LinearLayoutManager(activity)
binding.bSubmit.setOnClickListener{
val foodTitle= binding.etName.text.toString()
if (foodTitle.isNotEmpty()){
val food= food(foodTitle, binding.etCalories.text.toString().toInt(), false )
foodlistadapter.addFood(food)
binding.etName.text.clear()
binding.etCalories.text.clear()
}
}
binding.bDelete.setOnClickListener{
foodlistadapter.deleteFood()
}
}
override fun onDestroy() {
super.onDestroy()
_binding = null
}
}
foodlistadapter.kt
package com.example.bbar.ui.home
import android.annotation.SuppressLint
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.example.bbar.R
import android.graphics.Paint.STRIKE_THRU_TEXT_FLAG
import android.widget.TextView
import com.example.bbar.databinding.FooditemBinding
@SuppressLint("StaticFieldLeak")
private var _binding: FooditemBinding? = null
private val binding get() = _binding!!
class Foodlistadapter(
private val foods: MutableList<food>
) : RecyclerView.Adapter<Foodlistadapter.foodlistviewholder>() {
class foodlistviewholder(itemView: View) : RecyclerView.ViewHolder(itemView)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): foodlistviewholder {
return foodlistviewholder(
LayoutInflater.from(parent.context).inflate(
R.layout.fragment_home,
parent,
false
)
)
}
fun addFood(food: food) {
foods.add(food)
notifyItemInserted(foods.size - 1)
}
fun deleteFood() {
foods.removeAll { foods -> foods.isChecked }
notifyDataSetChanged()
}
private fun toggleStrikeThrough(tvFood: TextView, isChecked: Boolean) {
if (isChecked) {
tvFood.paintFlags = tvFood.paintFlags or STRIKE_THRU_TEXT_FLAG
} else {
tvFood.paintFlags = tvFood.paintFlags or STRIKE_THRU_TEXT_FLAG.inv()
}
}
override fun onBindViewHolder(holder: foodlistviewholder, position: Int) {
val currentFood = foods[position]
holder.itemView.apply {
binding.tvFood.text = currentFood.name
binding.tvCalories.text= currentFood.calories.toString()
binding.cbDelete.isChecked = currentFood.isChecked
toggleStrikeThrough(binding.tvFood, currentFood.isChecked)
binding.cbDelete.setOnCheckedChangeListener { _, isChecked ->
toggleStrikeThrough(binding.tvFood, isChecked)
currentFood.isChecked = !currentFood.isChecked
}
}
}
override fun getItemCount(): Int {
return foods.size
}
}
food.kt
package com.example.bbar.ui.home
data class food (
val name : String,
val calories: Int,
var isChecked: Boolean,
)
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
方法上。
你重复两次膨胀了你的视图,而在分配给它充气后没有使用绑定。
简而言之,
- 通过
FragmentHomeBinding.inflate
充气一个视图,并将绑定分配给它。 - 没有使用该充气的视图,而是通过
inflater.inflate(...)
再次充气了一个新视图,并使用这个新视图。
简单地使用:
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentHomeBinding.inflate(inflater, container, false)
return binding!!.root
}
英文:
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,
- You are inflating a view via
FragmentHomeBinding.inflate
, assigning the binding to it. - Not using that inflated view but inflating another via
inflater.inflate(...)
& using this new view.
Simply use:
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentHomeBinding.inflate(inflater, container, false)
return binding!!.root
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论