如何使用双向数据绑定更新 RecyclerView 中所有 EditTexts 元素的文本

Fah*_*Can 15 android android-edittext kotlin android-recyclerview two-way-binding

我有一个RecyclerView持有一些CardViews并且每个CardView包含的EditText乘以用户给出倍特定速率(速率来自一个端点,价格为每行不同)。对于CardViews,我使用数据绑定。

应用用例:

该应用程序应显示其他货币的金额,例如 2、7.89、14.34 或 110 欧元。

  1. 用户在任何行中输入一个金额(在EditText 中),每行都有一个具有不同值的“ rate ”(速率来自 API 端点)字段
  2. 用户输入的金额乘以“ rate
  3. RecyclerView 中的每一行都应该更新

现在的问题是如何使用双向数据绑定更新RecyclerView中所有 EditTexts 元素的文本

这是我用于数据绑定的数据类:

data class CurrencyItem(
    var flag: String,
    var shortName: String,
    var fullName: String,
    var rate: Double
) : BaseObservable() {

    @Bindable
    var rateTimesAmount: String = (CurrencyApplication.userEnteredAmount * rate).toString()
        set(amount) {
            val amountAsDouble = amount.toDouble()
            val number2digits: Double = String.format("%.2f", amountAsDouble).toDouble()
            CurrencyApplication.userEnteredAmount = number2digits
            field = number2digits.toString()
            notifyPropertyChanged(BR.rateTimesAmount)
        }

}
Run Code Online (Sandbox Code Playgroud)

这是我在 item_currency.xml 中的 EditText

<EditText
                android:id="@+id/currency_rate"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginEnd="16dp"
                android:imeOptions="actionDone"
                android:inputType="numberDecimal"
                android:lines="1"
                android:maxLength="8"
                android:text="@={currency.rateTimesAmount}"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintTop_toTopOf="parent"
                tools:text="1183.068" />
Run Code Online (Sandbox Code Playgroud)

这是我的Application类,用于存储用户输入的金额:

class CurrencyApplication : Application() {

    companion object {
        var userEnteredAmount: Double = 1.00
    }

}
Run Code Online (Sandbox Code Playgroud)

这里我通过 Kotlin Android Extensions访问RecyclerView

recycler_view.apply {
            setHasFixedSize(true)
            itemAnimator = DefaultItemAnimator()
            adapter = currencyAdapter
        }
Run Code Online (Sandbox Code Playgroud)

这是activity_main.xml 中的RecyclerView

<androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_margin="8dp"
        android:clipToPadding="false"
        android:paddingBottom="8dp"
        android:scrollbars="vertical"
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
Run Code Online (Sandbox Code Playgroud)

这里是适配器RecyclerView

class CurrencyAdapter(
    val currencies: ArrayList<CurrencyItem>
) : RecyclerView.Adapter<CurrencyViewHolder>() {
    
    override fun getItemCount() = currencies.size

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CurrencyViewHolder {
        val itemCurrencyBinding: ItemCurrencyBinding = DataBindingUtil.inflate(
            LayoutInflater.from(parent.context),
            R.layout.item_currency,
            parent,
            false
        )
        return CurrencyViewHolder(itemCurrencyBinding)
    }

    override fun onBindViewHolder(holder: CurrencyViewHolder, position: Int) {
        holder.itemCurrencyBinding.currency = currencies[position]
    }

    fun setUpCurrencies(newCurrencies: List<CurrencyItem>) {
        currencies.clear()
        currencies.addAll(newCurrencies)
        notifyDataSetChanged()
    }
}

class CurrencyViewHolder(val itemCurrencyBinding: ItemCurrencyBinding) :
    RecyclerView.ViewHolder(itemCurrencyBinding.root)
Run Code Online (Sandbox Code Playgroud)

dia*_*use 1

您可能想Observable在您的 viewModel 或适配器中创建另一个,并将其作为变量绑定到适配器项。

就像这样:

class CurrencyAdapter: RecyclerView.Adapter<...>() {

    val rate = ObservableField(0.0)

    override fun onCreateViewHolder(
        parent: ViewGroup,
        viewType: Int
    ): RecyclerView.ViewHolder {
        val inflater = LayoutInflater.from(parent.context)
        val binding = DataBindingUtil.inflate<ViewDataBinding>(inflater, viewType, parent, false)
        binding.setVariable(BR.rate, rate)
        return YourViewHolder(binding.root)
    }

}
Run Code Online (Sandbox Code Playgroud)

如果您遇到其他视图急于更新速率变量的问题,请尝试创建自定义数据绑定适配器,以仅允许视图在获得焦点时触发更新。

@BindingAdapter("android:textAttrChanged")
fun TextView.setOnTextAttrChangedInFocus(listener: InverseBindingListener) {
    addTextChangedListener(afterTextChanged = {
        if(isFocused) {
            listener.onChange()
        }
    })
}
Run Code Online (Sandbox Code Playgroud)

(示例使用 androidx.core 扩展)

我希望它有帮助;)


查看Teanity,它可能会帮助您更快地弄清楚类似的事情。