gpt4 book ai didi

android - 自定义 View 的两种方式绑定(bind)

转载 作者:太空狗 更新时间:2023-10-29 16:26:49 24 4
gpt4 key购买 nike

我在 android 中有一个组合 View ,其中包含多个 textView 和一个 EditText。我为我的自定义 View 定义了一个名为 textgetTextsetText 方法的属性。现在我想为我的自定义 View 添加一个双向数据绑定(bind),以绑定(bind)到内部编辑文本的方式,所以如果我的数据得到更新,编辑文本也应该更新(现在可以),当我的编辑文本得到更新时,我的数据也应该更新。

我的绑定(bind)类看起来像这样

@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();
}
});
}
}
}

我尝试用下面的代码绑定(bind)文本。 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}"
/>

当我运行这个项目时,我得到了这个错误

Error:(20, 13) Could not find event 'textAttrChanged' on View type 'ir.avalinejad.pasargadinsurance.component.ErrorInputLayout'

我的自定义 View 是这样的

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);
}
}

最佳答案

经过几个小时的调试,我找到了解决方案。我像这样更改了我的绑定(bind)类。

@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 方法也在这里。

关于android - 自定义 View 的两种方式绑定(bind),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48211656/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com