我在android中有一个编译视图包含几个textView和一个EditText。我为自定义视图定义了一个名为text
和getText
,setText
方法的属性。现在我想以一种绑定到内部编辑文本的方式为我的自定义视图添加双向数据绑定,这样如果我的数据得到更新,编辑文本也应该更新(现在可以正常工作)和编辑时文本更新我的数据也应该更新。
我的绑定类看起来像这样
@InverseBindingMethods({
@InverseBindingMethod(type = ErrorInputLayout.class, attribute = "text"),
})
public class ErrorInputBinding {
@BindingAdapter(value = "text")
public static void setListener(ErrorInputLayout errorInputLayout, final InverseBindingListener textAttrChanged) {
if (textAttrChanged != null) {
errorInputLayout.getInputET().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) {
textAttrChanged.onChange();
}
});
}
}
}
我尝试使用下面的代码绑定文本。 userInfo
是一个可观察的类。
<ir.avalinejad.pasargadinsurance.component.ErrorInputLayout
android:id="@+id/one_first_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:title="@string/first_name"
app:text="@={vm.userInfo.firstName}"
/>
当我运行项目时,我收到此错误
错误:(20,13)无法找到事件&#39; textAttrChanged&#39;在视图类型&#39; ir.avalinejad.pasargadinsurance.component.ErrorInputLayout&#39;
我的自定义视图看起来像这样
public class ErrorInputLayout extends LinearLayoutCompat implements TextWatcher {
protected EditText inputET;
protected TextView errorTV;
protected TextView titleTV;
protected TextView descriptionTV;
private int defaultGravity;
private String title;
private String description;
private String hint;
private int inputType = -1;
private int lines;
private String text;
private Subject<Boolean> isValidObservable = PublishSubject.create();
private Map<Validation, String> validationMap;
public ErrorInputLayout(Context context) {
super(context);
init();
}
public ErrorInputLayout(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
readAttrs(attrs);
init();
}
public ErrorInputLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
readAttrs(attrs);
init();
}
private void readAttrs(AttributeSet attrs){
TypedArray a = getContext().getTheme().obtainStyledAttributes(
attrs,
R.styleable.ErrorInputLayout,
0, 0);
try {
title = a.getString(R.styleable.ErrorInputLayout_title);
description = a.getString(R.styleable.ErrorInputLayout_description);
hint = a.getString(R.styleable.ErrorInputLayout_hint);
inputType = a.getInt(R.styleable.ErrorInputLayout_android_inputType, -1);
lines = a.getInt(R.styleable.ErrorInputLayout_android_lines, 1);
text = a.getString(R.styleable.ErrorInputLayout_text);
} finally {
a.recycle();
}
}
private void init(){
validationMap = new HashMap<>();
setOrientation(VERTICAL);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
titleTV = (TextView) LayoutInflater.from(getContext()).inflate(R.layout.error_layout_default_title_textview, null, false);
addView(titleTV);
descriptionTV = (TextView) LayoutInflater.from(getContext()).inflate(R.layout.error_layout_default_description_textview, null, false);
addView(descriptionTV);
readInputFromLayout();
if(inputET == null) {
inputET = (EditText) LayoutInflater.from(getContext()).inflate(R.layout.error_layout_defult_edittext, this, false);
addView(inputET);
}
errorTV = (TextView) LayoutInflater.from(getContext()).inflate(R.layout.error_layout_default_error_textview, null, false);
addView(errorTV);
inputET.addTextChangedListener(this);
defaultGravity = inputET.getGravity();
//set values
titleTV.setText(title);
if(description != null && !description.trim().isEmpty()){
descriptionTV.setVisibility(VISIBLE);
descriptionTV.setText(description);
}
if(inputType != -1)
inputET.setInputType(inputType);
if(hint != null)
inputET.setHint(hint);
else
inputET.setHint(title);
inputET.setLines(lines);
inputET.setText(text);
}
private void readInputFromLayout() {
if(getChildCount() > 3){
throw new IllegalStateException("Only one or zero view is allow in layout");
}
if(getChildCount() == 3){
View view = getChildAt(2);
if(view instanceof EditText)
inputET = (EditText) view;
else
throw new IllegalStateException("only EditText is allow as child view");
}
}
public void setText(String text){
inputET.setText(text);
}
public String getText() {
return text;
}
public void addValidation(@NonNull Validation validation, @StringRes int errorResourceId){
addValidation(validation, getContext().getString(errorResourceId));
}
public void addValidation(@NonNull Validation validation, @NonNull String error){
if(!validationMap.containsKey(validation))
validationMap.put(validation, error);
}
public void remoteValidation(@NonNull Validation validation){
if(validationMap.containsKey(validation))
validationMap.remove(validation);
}
public EditText getInputET() {
return inputET;
}
public TextView getErrorTV() {
return errorTV;
}
@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) {
checkValidity();
if(editable.toString().length() == 0) //if hint
inputET.setGravity(Gravity.RIGHT);
else
inputET.setGravity(defaultGravity);
}
public Subject<Boolean> getIsValidObservable() {
return isValidObservable;
}
private void checkValidity(){
//this function only shows the first matched error.
errorTV.setVisibility(INVISIBLE);
for(Validation validation: validationMap.keySet()){
if(!validation.isValid(inputET.getText().toString())) {
errorTV.setText(validationMap.get(validation));
errorTV.setVisibility(VISIBLE);
isValidObservable.onNext(false);
return;
}
}
isValidObservable.onNext(true);
}
}
答案 0 :(得分:4)
经过数小时的调试,我找到了解决方案。我改变了我的Binding类。
@InverseBindingMethods({
@InverseBindingMethod(type = ErrorInputLayout.class, attribute = "text"),
})
public class ErrorInputBinding {
@BindingAdapter(value = "textAttrChanged")
public static void setListener(ErrorInputLayout errorInputLayout, final InverseBindingListener textAttrChanged) {
if (textAttrChanged != null) {
errorInputLayout.getInputET().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) {
textAttrChanged.onChange();
}
});
}
}
@BindingAdapter("text")
public static void setText(ErrorInputLayout view, String value) {
if(value != null && !value.equals(view.getText()))
view.setText(value);
}
@InverseBindingAdapter(attribute = "text")
public static String getText(ErrorInputLayout errorInputLayout) {
return errorInputLayout.getText();
}
首先,我在AttrChanged
这样的文本之后添加@BindingAdapter(value = "textAttrChanged")
,这是监听器的默认名称,然后我在这里添加了getter和setter方法。
答案 1 :(得分:2)
event = "android:textAttrChanged"
为我工作:
object DataBindingUtil {
@BindingAdapter("emptyIfZeroText") //replace "android:text" on EditText
@JvmStatic
fun setText(editText: EditText, text: String?) {
if (text == "0" || text == "0.0") editText.setText("") else editText.setText(text)
}
@InverseBindingAdapter(attribute = "emptyIfZeroText", event = "android:textAttrChanged")
@JvmStatic
fun getText(editText: EditText): String {
return editText.text.toString()
}
}
答案 2 :(得分:1)
您还需要添加一项功能
@BindingAdapter("app:textAttrChanged")
fun ErrorInputLayout.bindTextAttrChanged(listener: InverseBindingListener) {
}