>

데이터 바인딩을 통해 셀이 채워진 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);
        }
    };

구현은 다른 곳에서 취해졌지만 프로세스를 완전히 이해하지 못했다는 것을 인정하므로 설명도 높이 평가됩니다.


  • 답변 # 1

    문제를 해결하는 몇 가지 방법을 생각할 수 있습니다. 첫 번째는 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);
        }
    }
    
    

관련 자료

  • 이전 kotlin - embedId가있는 findAllBy JPA
  • 다음 php - 라 라벨은 MySQL 로그인 정보를받지 않습니다