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

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

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(&quot;StaticFieldLeak&quot;)
private var _binding: FooditemBinding? = null
private val binding get() =  _binding!!

class Foodlistadapter(

    private val foods: MutableList&lt;food&gt;
) : RecyclerView.Adapter&lt;Foodlistadapter.foodlistviewholder&gt;() {

    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 -&gt; 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 -&gt;
                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方法上。
你重复两次膨胀了你的视图,而在分配给它充气后没有使用绑定。

简而言之,

  1. 通过FragmentHomeBinding.inflate充气一个视图,并将绑定分配给它。
  2. 没有使用该充气的视图,而是通过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,

  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:

override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?,
    savedInstanceState: Bundle?
): View {
    _binding = FragmentHomeBinding.inflate(inflater, container, false)
    return binding!!.root
}

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:

确定