我们可以更改同一片段上的 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 被调用并显示(现已更改)数据
  • ViewHolderTextView 设置为显示新数据

所以在这种情况下,您根本不需要直接修改 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)
    }
}

注意事项:

  1. 您不能用一个 binding 实例来处理回收站视图的所有项目。为此,我们有 ViewHolder
  2. 将您的绑定逻辑以及与 ViewHolder 中每个单独项目相关的所有内容保留下来。这就是它的意义。
  3. 尽量让您的适配器保持简单,只编写表示逻辑。将所有业务逻辑保留在适配器之外。
  4. 接口是您最好的朋友。这支持第 3 点。让您的 activity / 片段实现这些接口并将实例传递给 Adapter 构造函数 val variantsAdapter = RecyclerViewAdapter(this, this)。这将允许您在 Recycler View 适配器之外编写业务逻辑(包括上下文所需的语句,例如调用不同的 activity 或启动服务或在您的情况下进行 API 调用)

如有任何问题,请随时与我们联系。