我有一个RecyclerView,其单元是通过数据绑定填充的。每个单元代表一个购物车的项目。每个单元格都包含一个EditText,它负责购物车中的产品数量。该数量在我的ViewModel中被重新定义为 observableInt 。当数量发生变化时,我想采取行动,并且为observableInt参数设置了 OnPropertyChangedCallback 侦听器。如果我使用 app:addTextChangedListener =“ @ {cartItemVM.quantityInputTextWatcher}” 来获取值并将其设置为可观察值,则其监听器将被调用多次(这也是因为我可以更改以及一些+-按钮的EditText值)。
我遇到了双向数据绑定,但是仍然无法使它起作用。这是我到目前为止的内容:
<QuantityEditText
android:id="@+id/etQuantityInput"
android:text="@{String.valueOf(cartItemVM.totalInCart)}"
quantity="@={cartItemVM.totalInCart}"
onQuantityChange="@{cartItemVM.onQuantityChange}"
这是我自定义的EditText:
public class QuantityEditText extends CustomEditText {
private int quantity;
private OnQuantityChangeListener onQuantityChangeListener;
public interface OnQuantityChangeListener {
void onQuantityChange(QuantityEditText view, int quantity);
}
这是我的ViewModel类:
@InverseBindingMethods({
@InverseBindingMethod(type = QuantityEditText.class, attribute = "quantity")
})
public class ProductInCartObservableViewModel{
public final ObservableInt totalInCart;
@BindingAdapter(value = {"onQuantityChange", "quantityAttrChanged"},
requireAll = false)
public static void setQuantityAttrChanged(QuantityEditText view,
final QuantityEditText.OnQuantityChangeListener listener,
final InverseBindingListener quantityChange) {
if (quantityChange == null) {
view.setOnQuantityChangeListener(listener);
} else {
view.setOnQuantityChangeListener(new QuantityEditText.OnQuantityChangeListener() {
@Override
public void onQuantityChange(QuantityEditText view, int quantity) {
if (listener != null) {
listener.onQuantityChange(view, quantity);
}
view.setText(String.valueOf(quantity));
quantityChange.onChange();
}
});
}
}
@BindingAdapter("quantity")
public static void setQuantity(QuantityEditText view, int quantity) {
if (quantity != view.getQuantity()) {
view.setQuantity(quantity);
}
}
@InverseBindingAdapter(attribute = "quantity")
public static int getQuantity(QuantityEditText view) {
int val = 0;
if (!TextUtils.isEmpty(view.getText().toString())) {
try {
val = Integer.valueOf(view.getText().toString());
} catch (IllegalArgumentException e) {
Timber.e(e);
}
}
// Won't let the user remove product from cart using the editText
if (val <= 0) {
val = 1;
}
if (val > 150) {
val = 150;
}
return val;
}
public QuantityEditText.OnQuantityChangeListener onQuantityChange = new QuantityEditText.OnQuantityChangeListener() {
@Override
public void onQuantityChange(QuantityEditText view, int quantity) {
if (quantity <= 0) {
quantity = 0;
}
if (quantity > 150) {
quantity = 150;
}
totalInCart.set(quantity);
}
};
实现是从不同的地方进行的,但我承认我还没有完全理解该过程,因此也将不胜感激。
答案 0 :(得分:0)
我可以想到几种解决问题的方法。第一种是避免QuatityEditText,而直接设置数字。我更喜欢使用转换方法来定制双向绑定,因为它们往往更易于实现:
@InverseMethod("stringToInt")
public static String intToString(TextView view, int oldValue, int value) {
NumberFormat numberFormat = getNumberFormat(view);
try {
String inView = view.getText().toString();
int parsed = numberFormat.parse(inView).intValue();
if (parsed == value) {
return view.getText().toString();
}
} catch (ParseException e) {
// old number was broken
}
return numberFormat.format(value);
}
public static int stringToInt(TextView view, int oldValue, String value) {
NumberFormat numberFormat = getNumberFormat(view);
try {
return numberFormat.parse(value).intValue();
} catch (ParseException e) {
view.setError("Improper number format");
return oldValue;
}
}
private static NumberFormat getNumberFormat(View view) {
Resources resources= view.getResources();
Locale locale = resources.getConfiguration().locale;
NumberFormat format =
NumberFormat.getNumberInstance(locale);
if (format instanceof DecimalFormat) {
DecimalFormat decimalFormat = (DecimalFormat) format;
decimalFormat.setGroupingUsed(false);
}
return format;
}
并且布局具有:
<EditText ...
android:id="@+id/etQuantityInput"
android:inputType="number"
android:text="@={Converter.intToString(etQuantityInput, cartItemVM.totalInCart, cartItemVM.totalInCart)}"/>
如果您要一个新的quantityEditText,我认为最好是用一个属性来控制它,而不是同时使用字符串文本和int数量:
<QuantityEditText ...
android:id="@+id/etQuantityInput"
android:inputType="number"
app:quantity="@={cartItemVM.totalInCart)}"/>
这是我整理的课,以使数量遵循文本:
public class QuantityEditText extends android.support.v7.widget.AppCompatEditText {
public QuantityEditText(Context context) {
super(context);
initTextWatcher();
}
public QuantityEditText(Context context, AttributeSet attrs) {
super(context, attrs);
initTextWatcher();
}
public QuantityEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initTextWatcher();
}
private int quantity;
private OnQuantityChangeListener onQuantityChangeListener;
void initTextWatcher() {
addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void afterTextChanged(Editable editable) {
updateQuantityFromText();
}
});
}
public void setQuantity(int quantity) {
if (updateQuantity(quantity)) {
setText(getNumberFormat().format(quantity));
}
}
public int getQuantity() {
return quantity;
}
private boolean updateQuantity(int newQuantity) {
if (this.quantity == newQuantity) {
return false; // nothing to do
}
this.quantity = newQuantity;
if (onQuantityChangeListener != null) {
onQuantityChangeListener.onQuantityChange(this, quantity);
}
return true;
}
void updateQuantityFromText() {
try {
String inView = getText().toString();
updateQuantity(getNumberFormat().parse(inView).intValue());
} catch (ParseException e) {
// Problem with the string format, so just don't update the quantity
}
}
private NumberFormat getNumberFormat() {
Resources resources = getResources();
Locale locale = resources.getConfiguration().locale;
NumberFormat format =
NumberFormat.getNumberInstance(locale);
if (format instanceof DecimalFormat) {
DecimalFormat decimalFormat = (DecimalFormat) format;
decimalFormat.setGroupingUsed(false);
}
return format;
}
public void setOnQuantityChangeListener(OnQuantityChangeListener listener) {
onQuantityChangeListener = listener;
}
public interface OnQuantityChangeListener {
void onQuantityChange(QuantityEditText view, int quantity);
}
}
您还需要一种方法来设置InverseBindingListener并为数量设置双向数据绑定:
@InverseBindingMethods(
@InverseBindingMethod(type = QuantityEditText.class, attribute = "quantity")
)
public class BindingAdapters {
@BindingAdapter("quantityAttrChanged")
public static void setQuantityAttrChanged(QuantityEditText view,
final InverseBindingListener quantityChange) {
QuantityEditText.OnQuantityChangeListener listener = null;
if (quantityChange != null) {
listener = new QuantityEditText.OnQuantityChangeListener() {
@Override
public void onQuantityChange(QuantityEditText view, int quantity) {
quantityChange.onChange();
}
};
}
view.setOnQuantityChangeListener(listener);
}
}