我们可以更改同一片段上的 textview 吗?
can we change textview being on same fragment?
我正在开发一个演示应用程序,每当我在 recycler 视图的同一项目中更改 edittext 的值时,我必须更新 recyclerview 中项目的 texview。以下是我的 rcv 适配器。
class RecyclerViewAdapterU (val dataList:ArrayList<ModelClass>): RecyclerView.Adapter<RecyclerViewAdapterU.ViewHolder>() {
var _binding: UploadItemViewBinding? = null
val binding get() = _binding!!
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): RecyclerViewAdapterU.ViewHolder {
val v =
LayoutInflater.from(parent.context).inflate(R.layout.upload_item_view, parent, false)
_binding = UploadItemViewBinding.bind(v)
return ViewHolder(binding.root)
}
override fun onBindViewHolder(holder: ViewHolder, @SuppressLint("RecyclerView") position: Int) {
bindItems(dataList[position])
holder.getStock()
holder.updateStockDetail()
}
fun bindItems(data: ModelClass) {
binding.itemquant.text = data.item_quant
binding.uploadItemName.text = data.item_name
binding.uploadMfg.text = data.mfg
binding.skuStock.setText(data.item_stock.toString())
binding.skuCode.setText(data.sku_code)
}
override fun getItemCount(): Int {
return dataList.size
}
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var stockdetail = ArrayList<ModelClass>()
fun getStock() {
binding.skuStock.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {}
override fun onTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {}
override fun afterTextChanged(editable: Editable) {
for (i in 0 until RecyclerViewAdapter.ob.dataSelected.size){
if (editable.toString().trim()!=""){
var x= editable.toString().trim().toInt()
RecyclerViewAdapter.ob.dataSelected[adapterPosition].item_stock=x
}
}
}
})
}
fun updateStockDetail(){
binding.skuCode.addTextChangedListener(object : TextWatcher{
override fun beforeTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {}
override fun onTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {
}
override fun afterTextChanged(editable: Editable) {
if (editable.length==3){
var x:String
for (i in 0 until RecyclerViewAdapter.ob.dataSelected.size){
if (editable.toString().trim()!=""){
x=editable.toString().trim()
RecyclerViewAdapter.ob.dataSelected[adapterPosition].sku_code=x
println("$x in if")
}
}
println(RecyclerViewAdapter.ob.dataSelected[adapterPosition].sku_code)
getUpdatedDetails(RecyclerViewAdapter.ob.dataSelected[adapterPosition].sku_code)
for (i in stockdetail){
bindItems(i)
//binding.uploadItemName.text=i.item_name
println(i.item_name)
}
}
}
})
}
fun getUpdatedDetails(skucode:String){
val call: Call<List<ModelClass>>? =
ApiClient.instance?.myApi?.getfromsku(skucode)!!
call!!.enqueue(object : Callback<List<ModelClass>?> {
override fun onResponse(
call: Call<List<ModelClass>?>,
response: Response<List<ModelClass>?>
) {
val skuDetails=response.body()
stockdetail.clear()
if (skuDetails != null) {
for (i in skuDetails){
println(i.item_name)
stockdetail.addAll(skuDetails)
}
}
}
override fun onFailure(call: Call<List<ModelClass>?>, t: Throwable) {
}
})
}
}
}
查看 updatestockdetail 函数。不确定我做的是否正确..如果不对,有人可以帮助我以正确的方式做吗?
问题的详细解释。
Screenshot
在此图像中,B20 是 Bingo20gm 的 sku 代码。同样,L20 用于 Lays20gm,因此如果我将 B20 更改为 L20,则显示 Bingo 20gm 的文本视图应更改为 Lays 20gm。
数据由 API 传送,我在 getupdateddetails() 中调用它,并将它们放入列表中。
这更像是一个代码审查问题,但我认为你过于复杂了。
当您使用 RecyclerView
(或实际上任何列表小部件)时,您有三个部分:
- 您的数据
- 显示数据的东西(在本例中为
RecyclerView
)
- 获取数据并计算出如何显示它的东西(
Adapter
)
在 RecyclerView
中,数据以称为 ViewHolder
的迷你布局显示。不是为每个项目创建一个,而是创建一个它们的池,当 ViewHolder
滚出视图时,它会 回收 (重新使用)以显示一个新项目 - 这这就是为什么它被称为 RecyclerView
(而不是 ListView
)
所以每个 ViewHolder
都是可以显示项目详细信息的东西,当调用 onBindViewHolder
时,适配器就会计算出如何表示您的 数据 使用 view holder - 例如设置文本、图像、颜色、选中状态等。您还可以在 ViewHolder
中添加一些变量并在绑定期间设置它们,因此您可以获得有关其当前显示内容的更多信息 - 设置 position
变量很常见。这样,您就可以在 ViewHolder
中放置一些代码来处理它当前表示的数据。
要点是,您可以使 ViewHolder
这个 self-contained 组件:
- 有一个
EditText
和一个TextView
- 在
EditText
创建时设置 TextWatcher
- 每当
EditText
内容更改时更新 TextView
这些都是 ViewHolder
的内部内容,它只是在自己的布局中连接组件
如果您需要 ViewHolder
来推送一些信息(例如您输入的文本,或“单击按钮”事件),您可能需要在适配器中放置一个它可以调用的函数:
fun updateThing(data: String, position: Int) {
// update your data sources, do any validation, etc
// call notifyDataSetChanged() or similar, if required
}
如果您的 ViewHolder
中有一个 position
变量(您在 onBindViewHolder
期间设置),那么 VH 只需要在调用该函数时传递该变量。嘿,这是一个更新,我正在显示位置 X,这是新数据。这样,VH 只关心 UI 的东西,所有数据逻辑都在适配器中保持独立 - 并且可以做一些事情,比如决定列表是否需要更新。
这样做的另一个原因是,适配器也处理来自 其他 源的更新,例如您的 API 调用。所以如果你所有的数据更新逻辑都在一个地方,由一个东西处理,那就容易多了。这样,无论更新的来源如何,无论需要更新的原因是什么,都以相同的方式完成。如果适配器决定数据已更改,并且显示需要更新,则通过正常方法发生 - 即 onBindViewHolder
被调用,您在 RecyclerView
上设置当前数据。所以你可以得到这个事件链:
EditText
ViewHolder
更新
TextWatcher
代码使用新数据 调用适配器的 updateThing
函数
- 适配器存储新数据并强制显示更新
onBindViewHolder
被调用并显示(现已更改)数据
ViewHolder
的 TextView
设置为显示新数据
所以在这种情况下,您根本不需要直接修改 TextView
,您只需更新数据,作为该过程的一部分,新数据将直接显示。因为这就是数据更改时应该发生的情况,无论是什么导致数据更改。而且您无需担心是什么原因造成的,您只需显示它即可!
这是一个很长的答案,我显然没有重写您的代码,但希望它能让您更好地了解它的工作原理以及如何分离和简化它们。您的 ViewHolder
中有很多代码可以操纵数据、查看适配器、遍历其中的所有项目等等 - 它实际上应该只是显示内容并对 UI 事件做出反应。处理数据是适配器的工作
我尝试 re-working 使用您的代码,但有些事情没有意义,例如 RecyclerViewAdapter.ob.dataSelected
。您从哪里获得 RecyclerViewAdapter
实例?
因此,我在下方粘贴了一段我之前编写的适配器代码片段,它解决的问题与您的要求完全相同。
class RecyclerViewAdapter(
val interactionListener: InteractionListener,
val onTextChangedListener: OnTextChangedListener
) : RecyclerView.Adapter<RecyclerViewAdapter.OptionViewHolder>() {
private val variantsList = ArrayList<VariantsItem>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): OptionViewHolder {
val binding = SellVariantRowItemBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
return OptionViewHolder(binding)
}
override fun onBindViewHolder(holder: OptionViewHolder, position: Int) {
holder.bind(variantsList[position])
}
override fun getItemCount() = variantsList.size
fun updateVariantsList(newList: ArrayList<VariantsItem>) {
variantsList.clear()
variantsList.addAll(newList)
notifyDataSetChanged()
}
inner class OptionViewHolder(
private val binding: SellVariantRowItemBinding
) : RecyclerView.ViewHolder(binding.root) {
private var subVariant: String = ""
@SuppressLint("SetTextI18n")
fun bind(variantsItem: VariantsItem) {
subVariant = variantsItem.subVariant
binding.apply {
binding.root.tag = "pos_$bindingAdapterPosition"
sizeTv.text = "Size (${bindingAdapterPosition+1})"
variantValue.text = variantsItem.variant
subVariantValue.text = variantsItem.subVariant
quantityET.setText(variantsItem.quantity.toString().takeIf { it != "0" }?:"1")
sellingPriceET.setText(variantsItem.listingPrice.toString())
marketPriceET.setText(variantsItem.labelPrice.toString())
setOnClickListeners(variantsItem)
setTextChangeListeners(variantsItem)
}
}
private fun setTextChangeListeners(item: VariantsItem) {
binding.apply {
quantityET.addTextChangedListener {
if (it.toString().toIntOrNull() != null) {
onTextChangedListener.onQuantityChanged(
bindingAdapterPosition,
item.subVariant, item.variant,
it.toString()
)
}
}
marketPriceET.addTextChangedListener {
if (it.toString().toIntOrNull() != null) {
onTextChangedListener.onMarketPriceChanged(
bindingAdapterPosition,
item.subVariant,item.variant,
it.toString()
)
}
}
sellingPriceET.addTextChangedListener {
if (it.toString().toIntOrNull() != null){
onTextChangedListener.onSellingPriceChanged(
bindingAdapterPosition,
item.subVariant,item.variant,
it.toString()
)
}
}
}
}
private fun setOnClickListeners(variantsItem: VariantsItem) {
binding.apply {
deleteVariantBtn.setSafeOnClickListener {
interactionListener.onDeleteCard(variantsItem)
}
subVariantLayout.setSafeOnClickListener {
interactionListener.onChangeSubVariant(variantsItem)
}
variantLayout.setSafeOnClickListener {
interactionListener.onChangeVariant(variantsItem)
}
addNewVariant.setSafeOnClickListener {
it.pan()
interactionListener.onAddVariant(variantsItem.subVariant)
}
}
}
}
interface InteractionListener{
fun onChangeSubVariant(subToBeDeleted: VariantsItem)
fun onChangeVariant(variant: VariantsItem)
fun onDeleteCard(variant: VariantsItem)
fun onAddVariant(subVariantValue: String)
}
interface OnTextChangedListener{
fun onQuantityChanged(position: Int, subVariant: String, variant: String, quantity: String)
fun onMarketPriceChanged(position: Int, subVariant: String, variant: String, price: String)
fun onSellingPriceChanged(position: Int, subVariant: String, variant: String, price: String)
}
}
注意事项:
- 您不能用一个
binding
实例来处理回收站视图的所有项目。为此,我们有 ViewHolder
。
- 将您的绑定逻辑以及与 ViewHolder 中每个单独项目相关的所有内容保留下来。这就是它的意义。
- 尽量让您的适配器保持简单,只编写表示逻辑。将所有业务逻辑保留在适配器之外。
- 接口是您最好的朋友。这支持第 3 点。让您的 activity / 片段实现这些接口并将实例传递给 Adapter 构造函数
val variantsAdapter = RecyclerViewAdapter(this, this)
。这将允许您在 Recycler View 适配器之外编写业务逻辑(包括上下文所需的语句,例如调用不同的 activity 或启动服务或在您的情况下进行 API 调用)
如有任何问题,请随时与我们联系。
我正在开发一个演示应用程序,每当我在 recycler 视图的同一项目中更改 edittext 的值时,我必须更新 recyclerview 中项目的 texview。以下是我的 rcv 适配器。
class RecyclerViewAdapterU (val dataList:ArrayList<ModelClass>): RecyclerView.Adapter<RecyclerViewAdapterU.ViewHolder>() {
var _binding: UploadItemViewBinding? = null
val binding get() = _binding!!
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): RecyclerViewAdapterU.ViewHolder {
val v =
LayoutInflater.from(parent.context).inflate(R.layout.upload_item_view, parent, false)
_binding = UploadItemViewBinding.bind(v)
return ViewHolder(binding.root)
}
override fun onBindViewHolder(holder: ViewHolder, @SuppressLint("RecyclerView") position: Int) {
bindItems(dataList[position])
holder.getStock()
holder.updateStockDetail()
}
fun bindItems(data: ModelClass) {
binding.itemquant.text = data.item_quant
binding.uploadItemName.text = data.item_name
binding.uploadMfg.text = data.mfg
binding.skuStock.setText(data.item_stock.toString())
binding.skuCode.setText(data.sku_code)
}
override fun getItemCount(): Int {
return dataList.size
}
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var stockdetail = ArrayList<ModelClass>()
fun getStock() {
binding.skuStock.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {}
override fun onTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {}
override fun afterTextChanged(editable: Editable) {
for (i in 0 until RecyclerViewAdapter.ob.dataSelected.size){
if (editable.toString().trim()!=""){
var x= editable.toString().trim().toInt()
RecyclerViewAdapter.ob.dataSelected[adapterPosition].item_stock=x
}
}
}
})
}
fun updateStockDetail(){
binding.skuCode.addTextChangedListener(object : TextWatcher{
override fun beforeTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {}
override fun onTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {
}
override fun afterTextChanged(editable: Editable) {
if (editable.length==3){
var x:String
for (i in 0 until RecyclerViewAdapter.ob.dataSelected.size){
if (editable.toString().trim()!=""){
x=editable.toString().trim()
RecyclerViewAdapter.ob.dataSelected[adapterPosition].sku_code=x
println("$x in if")
}
}
println(RecyclerViewAdapter.ob.dataSelected[adapterPosition].sku_code)
getUpdatedDetails(RecyclerViewAdapter.ob.dataSelected[adapterPosition].sku_code)
for (i in stockdetail){
bindItems(i)
//binding.uploadItemName.text=i.item_name
println(i.item_name)
}
}
}
})
}
fun getUpdatedDetails(skucode:String){
val call: Call<List<ModelClass>>? =
ApiClient.instance?.myApi?.getfromsku(skucode)!!
call!!.enqueue(object : Callback<List<ModelClass>?> {
override fun onResponse(
call: Call<List<ModelClass>?>,
response: Response<List<ModelClass>?>
) {
val skuDetails=response.body()
stockdetail.clear()
if (skuDetails != null) {
for (i in skuDetails){
println(i.item_name)
stockdetail.addAll(skuDetails)
}
}
}
override fun onFailure(call: Call<List<ModelClass>?>, t: Throwable) {
}
})
}
}
}
查看 updatestockdetail 函数。不确定我做的是否正确..如果不对,有人可以帮助我以正确的方式做吗?
问题的详细解释。 Screenshot 在此图像中,B20 是 Bingo20gm 的 sku 代码。同样,L20 用于 Lays20gm,因此如果我将 B20 更改为 L20,则显示 Bingo 20gm 的文本视图应更改为 Lays 20gm。 数据由 API 传送,我在 getupdateddetails() 中调用它,并将它们放入列表中。
这更像是一个代码审查问题,但我认为你过于复杂了。
当您使用 RecyclerView
(或实际上任何列表小部件)时,您有三个部分:
- 您的数据
- 显示数据的东西(在本例中为
RecyclerView
) - 获取数据并计算出如何显示它的东西(
Adapter
)
在 RecyclerView
中,数据以称为 ViewHolder
的迷你布局显示。不是为每个项目创建一个,而是创建一个它们的池,当 ViewHolder
滚出视图时,它会 回收 (重新使用)以显示一个新项目 - 这这就是为什么它被称为 RecyclerView
(而不是 ListView
)
所以每个 ViewHolder
都是可以显示项目详细信息的东西,当调用 onBindViewHolder
时,适配器就会计算出如何表示您的 数据 使用 view holder - 例如设置文本、图像、颜色、选中状态等。您还可以在 ViewHolder
中添加一些变量并在绑定期间设置它们,因此您可以获得有关其当前显示内容的更多信息 - 设置 position
变量很常见。这样,您就可以在 ViewHolder
中放置一些代码来处理它当前表示的数据。
要点是,您可以使 ViewHolder
这个 self-contained 组件:
- 有一个
EditText
和一个TextView
- 在
EditText
创建时设置TextWatcher
- 每当
EditText
内容更改时更新TextView
这些都是 ViewHolder
的内部内容,它只是在自己的布局中连接组件
如果您需要 ViewHolder
来推送一些信息(例如您输入的文本,或“单击按钮”事件),您可能需要在适配器中放置一个它可以调用的函数:
fun updateThing(data: String, position: Int) {
// update your data sources, do any validation, etc
// call notifyDataSetChanged() or similar, if required
}
如果您的 ViewHolder
中有一个 position
变量(您在 onBindViewHolder
期间设置),那么 VH 只需要在调用该函数时传递该变量。嘿,这是一个更新,我正在显示位置 X,这是新数据。这样,VH 只关心 UI 的东西,所有数据逻辑都在适配器中保持独立 - 并且可以做一些事情,比如决定列表是否需要更新。
这样做的另一个原因是,适配器也处理来自 其他 源的更新,例如您的 API 调用。所以如果你所有的数据更新逻辑都在一个地方,由一个东西处理,那就容易多了。这样,无论更新的来源如何,无论需要更新的原因是什么,都以相同的方式完成。如果适配器决定数据已更改,并且显示需要更新,则通过正常方法发生 - 即 onBindViewHolder
被调用,您在 RecyclerView
上设置当前数据。所以你可以得到这个事件链:
EditText
ViewHolder
更新TextWatcher
代码使用新数据 调用适配器的 - 适配器存储新数据并强制显示更新
onBindViewHolder
被调用并显示(现已更改)数据ViewHolder
的TextView
设置为显示新数据
updateThing
函数
所以在这种情况下,您根本不需要直接修改 TextView
,您只需更新数据,作为该过程的一部分,新数据将直接显示。因为这就是数据更改时应该发生的情况,无论是什么导致数据更改。而且您无需担心是什么原因造成的,您只需显示它即可!
这是一个很长的答案,我显然没有重写您的代码,但希望它能让您更好地了解它的工作原理以及如何分离和简化它们。您的 ViewHolder
中有很多代码可以操纵数据、查看适配器、遍历其中的所有项目等等 - 它实际上应该只是显示内容并对 UI 事件做出反应。处理数据是适配器的工作
我尝试 re-working 使用您的代码,但有些事情没有意义,例如 RecyclerViewAdapter.ob.dataSelected
。您从哪里获得 RecyclerViewAdapter
实例?
因此,我在下方粘贴了一段我之前编写的适配器代码片段,它解决的问题与您的要求完全相同。
class RecyclerViewAdapter(
val interactionListener: InteractionListener,
val onTextChangedListener: OnTextChangedListener
) : RecyclerView.Adapter<RecyclerViewAdapter.OptionViewHolder>() {
private val variantsList = ArrayList<VariantsItem>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): OptionViewHolder {
val binding = SellVariantRowItemBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
return OptionViewHolder(binding)
}
override fun onBindViewHolder(holder: OptionViewHolder, position: Int) {
holder.bind(variantsList[position])
}
override fun getItemCount() = variantsList.size
fun updateVariantsList(newList: ArrayList<VariantsItem>) {
variantsList.clear()
variantsList.addAll(newList)
notifyDataSetChanged()
}
inner class OptionViewHolder(
private val binding: SellVariantRowItemBinding
) : RecyclerView.ViewHolder(binding.root) {
private var subVariant: String = ""
@SuppressLint("SetTextI18n")
fun bind(variantsItem: VariantsItem) {
subVariant = variantsItem.subVariant
binding.apply {
binding.root.tag = "pos_$bindingAdapterPosition"
sizeTv.text = "Size (${bindingAdapterPosition+1})"
variantValue.text = variantsItem.variant
subVariantValue.text = variantsItem.subVariant
quantityET.setText(variantsItem.quantity.toString().takeIf { it != "0" }?:"1")
sellingPriceET.setText(variantsItem.listingPrice.toString())
marketPriceET.setText(variantsItem.labelPrice.toString())
setOnClickListeners(variantsItem)
setTextChangeListeners(variantsItem)
}
}
private fun setTextChangeListeners(item: VariantsItem) {
binding.apply {
quantityET.addTextChangedListener {
if (it.toString().toIntOrNull() != null) {
onTextChangedListener.onQuantityChanged(
bindingAdapterPosition,
item.subVariant, item.variant,
it.toString()
)
}
}
marketPriceET.addTextChangedListener {
if (it.toString().toIntOrNull() != null) {
onTextChangedListener.onMarketPriceChanged(
bindingAdapterPosition,
item.subVariant,item.variant,
it.toString()
)
}
}
sellingPriceET.addTextChangedListener {
if (it.toString().toIntOrNull() != null){
onTextChangedListener.onSellingPriceChanged(
bindingAdapterPosition,
item.subVariant,item.variant,
it.toString()
)
}
}
}
}
private fun setOnClickListeners(variantsItem: VariantsItem) {
binding.apply {
deleteVariantBtn.setSafeOnClickListener {
interactionListener.onDeleteCard(variantsItem)
}
subVariantLayout.setSafeOnClickListener {
interactionListener.onChangeSubVariant(variantsItem)
}
variantLayout.setSafeOnClickListener {
interactionListener.onChangeVariant(variantsItem)
}
addNewVariant.setSafeOnClickListener {
it.pan()
interactionListener.onAddVariant(variantsItem.subVariant)
}
}
}
}
interface InteractionListener{
fun onChangeSubVariant(subToBeDeleted: VariantsItem)
fun onChangeVariant(variant: VariantsItem)
fun onDeleteCard(variant: VariantsItem)
fun onAddVariant(subVariantValue: String)
}
interface OnTextChangedListener{
fun onQuantityChanged(position: Int, subVariant: String, variant: String, quantity: String)
fun onMarketPriceChanged(position: Int, subVariant: String, variant: String, price: String)
fun onSellingPriceChanged(position: Int, subVariant: String, variant: String, price: String)
}
}
注意事项:
- 您不能用一个
binding
实例来处理回收站视图的所有项目。为此,我们有ViewHolder
。 - 将您的绑定逻辑以及与 ViewHolder 中每个单独项目相关的所有内容保留下来。这就是它的意义。
- 尽量让您的适配器保持简单,只编写表示逻辑。将所有业务逻辑保留在适配器之外。
- 接口是您最好的朋友。这支持第 3 点。让您的 activity / 片段实现这些接口并将实例传递给 Adapter 构造函数
val variantsAdapter = RecyclerViewAdapter(this, this)
。这将允许您在 Recycler View 适配器之外编写业务逻辑(包括上下文所需的语句,例如调用不同的 activity 或启动服务或在您的情况下进行 API 调用)
如有任何问题,请随时与我们联系。