在Android中,我们可以在变量前面使用与@=
的双向数据绑定。但是,该变量是double
。因此,要在EditText
中显示,我需要使用String
将其转换为String.valueOf(pojo.value)
。
如果我在前面附加=
以进行双向数据绑定,那么它就不会编译。
如果我附加onTextChanged
并在那里设置值,我会丢失光标。有没有解决方法?
修改
它适用于InverseBindingAdapter
,但不允许输入.
(句号)。
答案 0 :(得分:1)
没有简单的解决方法。但是,我继续前进并创造了一种几乎像双向绑定一样的变化。
我的EditText看起来像这样:
<EditText
android:id="@+id/amount"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1.1"
android:digits="0123456789."
android:gravity="end"
android:inputType="numberDecimal|numberSigned"
android:onTextChanged="@{() -> handler.valueAmountChanged(amount)}"
android:selectAllOnFocus="true"
android:text="0"
android:textColor="@color/selector_disabled_edit_text"
app:userVal="@{userAmount}" />
handler
是活动的实例。它包含valueAmountChanged(EditText editText)
方法。
现在,在检查了您的价值金额时,我正在解析该文本字符串并将其存储在相应的变量中。
对我来说,它看起来像这样:
public void valueAmountChanged(EditText editText) {
double d = 0.0;
try {
String currentString = editText.getText().toString();
// Remove the 2nd dot if present
if (currentString.indexOf(".", currentString.indexOf(".") + 1) > 0)
editText.getText().delete(editText.getSelectionStart() - 1, editText.getSelectionEnd());
// Remove extra character after 2 decimal places
currentString = editText.getText().toString(); // get updated string
if (currentString.matches(".*\\.[0-9]{3}")) {
editText.getText().delete(currentString.indexOf(".") + 3, editText.length());
}
d = Double.valueOf(editText.getText().toString());
} catch (NumberFormatException e) {
}
userAmount = d; // this variable is set for binding
}
现在,当我们更改userAmount
变量时,它会反映出我们已在app:userVal
中使用EditText
参数设置绑定适配器。
因此,使用绑定适配器检查新值是否不是当前值,然后更新该值。否则,保持原样。我们需要这样做,因为如果用户正在键入并且绑定适配器更新该值,那么它将松散是光标位置并将其带到前面。所以,这将拯救我们。
@BindingAdapter({"userVal"})
public static void setVal(EditText editText, double newVal) {
String currentValue = editText.getText().toString();
try {
if (Double.valueOf(currentValue) != newVal) {
DecimalFormat decimalFormat = new DecimalFormat("#.##");
String val = decimalFormat.format(newVal);
editText.setText(val);
}
} catch (NumberFormatException exception) {
// Do nothing
}
}
这是一种典型的方法,我知道。但是,找不到比这更好的了。还有非常少的文档可用,其他文档以博客文章的形式出现,应该已添加到官方文档中。
希望它有所帮助。
答案 1 :(得分:1)
这就是我的做法。
//-------------------------------------------------------------------------------------------------//
@BindingAdapter("app:text")
fun setDoubleInTextView(tv: TextView, dbl: Double?) {
try {
//This will occur when view is first created or when the leading zero is omitted
if (dbl == null && (tv.text.toString() == "" || tv.text.toString() == ".")) return
//Check to see what's already there
val tvDbl = tv.text.toString().toDouble()
//If it's the same as what we've just entered then return
// This is when then the double was typed rather than binded
if (tvDbl == dbl)
return
//If it's a new number then set it in the tv
tv.text = dbl?.toString()
} catch (nfe: java.lang.NumberFormatException) {
//This is usually caused when tv.text is blank and we've entered the first digit
tv.text = dbl?.toString() ?: ""
}//catch
}//setDoubleInTextView
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -//
@InverseBindingAdapter(attribute = "app:text")
fun getDoubleFromTextView(editText: TextView): Double? {
return try {
editText.text.toString().toDouble()
} catch (e: NumberFormatException) {
null
}//catch
}//getDoubleFromTextView
//-------------------------------------------------------------------------------------------------//
@BindingAdapter("textAttrChanged")
fun setTextChangeListener(editText: TextView, listener: InverseBindingListener) {
editText.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(p0: Editable?) = listener.onChange()
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
Log.d(TAG, "beforeTextChanged $p0")
}
override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
Log.d(TAG, "onTextChanged $p0")
}
})
}
//-------------------------------------------------------------------------------------------------//
<EditText
style="@style/TextAppearance.MaterialComponents.Body1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="@string/price"
android:inputType="numberDecimal"
app:text="@={viewModel.tempProductPrice}"/>
EditText具有以下设置以强制正确输入
android:inputType="numberDecimal"
答案 2 :(得分:0)
您的解决方案部分适用于我。 我使用了@BindingAdaptor和&#39; Amount&#39;变量值反映在编辑文本中,但OnTextChangeListner没有在值更改时触发。所以我在VM中使用了TextWatcher。 VM和XML的代码都在这里。没有什么可写在活动中。
//VIEW MODEL
@SerializedName("Amount")
private Double Amount ;
@Bindable
public Double getAmount() {
return (Amount == null)? 0.0 : Amount;
}
public void setAmount(Double amount) {
Amount = amount;
notifyPropertyChanged(BR.amount);
}
public TextWatcher getAmountWatcher() {
return new SimpleTextWatcher() {
@Override
public void onTextChanged(String text) {
Amount =(text!=null&&text!="")?Double.valueOf(text):0.0;
}
};
}
@BindingAdapter({"userVal"})
public static void setVal(EditText editText, double newVal) {
String currentValue = editText.getText().toString();
try {
if (Double.valueOf(currentValue) != newVal) {
DecimalFormat decimalFormat = new DecimalFormat("#.##");
String val = decimalFormat.format(newVal);
editText.setText(val);
}
} catch (NumberFormatException exception) {
exception.printStackTrace();
}
}
//XML CODE
<com.mycompany.myproj.Widgets.MyEditText
android:id="@+id/expense_cost"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:inputType="numberDecimal"
android:maxLength="6"
android:selectAllOnFocus="true"
app:addTextChangedListener="@{expense.amountWatcher}"
app:userVal="@{expense.Amount}" />
干杯
答案 3 :(得分:0)
这对我有用:
<EditText
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
android:text="@={`` + viewModel.currentStudent.age}" //key point!! Not single/double quote
android:inputType="number" />