Android自定义视图和自定义Attr的双向数据绑定

我一直在为基本应用程序使用双向数据绑定,它很顺利,直到我开始使用自定义视图和attrs.

我想创建一个自定义视图,有一个TextView和一个EditText,并在另一个布局中使用它:

<TextView
    android:text="Holder"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/tvTitle"
    android:layout_weight="1" />

<EditText
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:inputType="none"
    android:text="Name"
    android:ems="10"
    android:id="@+id/etAnwser"
    android:layout_weight="1" />

我有它的自定义attr

<resources>
<declare-styleable name="form_item">
    <attr name="tvTitle" format="string" />
    <attr name="anwserHint" format="string" />
    <attr name="anwserText" format="string" />
    <attr name="android:enabled" />
</declare-styleable>

在片段中,我执行以下操作:

<rhcloud.com.financialcontrol.tabutil.FormItem
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:enabled="@{state.get()}"
            form_item:anwserText='@={expense.description}'
            form_item:tvTitle="Description:" />

它的单向数据绑定很好用,但无论我改变文本,他都不会在课堂上给我发回调

@InverseBindingMethods(value = {
        @InverseBindingMethod(type = FormItem.class,attribute = "anwserText"),})
public class FormItem extends LinearLayout {

    private TextView tvTitle;
    private EditText etAnwser;

    public FormItem(@NonNull Context context) {
        super(context);
        LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        inflater.inflate(R.layout.form_item,this);

        tvTitle = (TextView) findViewById(R.id.tvTitle);
        etAnwser = (EditText) findViewById(R.id.etAnwser);
    }

    public FormItem(@NonNull Context context,@NonNull String title) {
        this(context);
        setTvTitle(title);
    }

    public FormItem(@NonNull Context context,@NonNull String title,@NonNull String hint) {
        this(context,title);
        setAnwserHint(hint);
    }

    public FormItem(@NonNull Context context,@NonNull String hint,@NonNull String anwserText) {
        this(context,title,hint);
        setAnwserHint(anwserText);
    }


    public FormItem(@NonNull Context context,@NonNull AttributeSet attrs) {
        super(context,attrs);

        LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        inflater.inflate(R.layout.form_item,this);

        tvTitle = (TextView) findViewById(R.id.tvTitle);
        etAnwser = (EditText) findViewById(R.id.etAnwser);

        TypedArray a = context.getTheme().obtainStyledAttributes(
                attrs,R.styleable.form_item,0);

        try {
            setTvTitle(a.getString(R.styleable.form_item_tvTitle));
            setAnwserHint(a.getString(R.styleable.form_item_anwserHint));
            setAnwserText(a.getString(R.styleable.form_item_anwserText));
            String isEnabled = a.getString(R.styleable.form_item_android_enabled);
            if (isEnabled != null) {
                setEnable(Boolean.parseBoolean(isEnabled));
            }
        } finally {
            a.recycle();
        }
    }

    public void setTvTitle(String title) {
        tvTitle.setText(title);
    }

    public String getTvTitle() {
        return tvTitle.getText().toString();
    }

    public void setAnwserHint(String hint) {
        etAnwser.setHint(hint);
    }

    public String getAnwserHint() {
        return etAnwser.getHint().toString();
    }

    public void setEnable(boolean isEnable) {
        tvTitle.setEnabled(isEnable);
        etAnwser.setEnabled(isEnable);
    }

    public void setAnwserText(String anwserText) {
        etAnwser.setText(anwserText);
    }

    public String getAnwserText() {
        return etAnwser.getText().toString();
    }

    @InverseBindingAdapter(attribute = "form_item:anwserText")
    public static String setOnAnwserTextAttrChanged(final String value){

        Log.d("Test","Calling InverseBindingAdapter: " + value);
        return value;
    }


    @BindingAdapter(value = {"anwserTextAttrChanged"},requireAll = false)
    public static void setOnAnwserTextAttrChanged(final FormItem view,final InverseBindingListener anwserTextAttrChanged){

        Log.d("Test","Calling BindingAdapter: " + view.getAnwserText());


    if(anwserTextAttrChanged == null){

        }else{
        Log.d("Test","Calling here");
            anwserTextAttrChanged.onChange();

        }
    }

    @BindingAdapter(value = {"android:enabled"})
    public static void customEnable(FormItem formItem,boolean isEnable) {
        formItem.setEnable(isEnable);
    }
}

有谁知道如何让它正常工作?

完全代码可以在here找到

解决方法

这对我有用:
@InverseBindingMethods(value = {
        @InverseBindingMethod(type = FilterPositionView.class,attribute = "bind:filterStringValue",method = "getFilterValue",event = "android:filterStringValuetAttrChanged")
})
public class FilterPositionView extends LinearLayout {
    private FilterPositionBinding mBinding;

    public FilterPositionView(Context context) {
        super(context);
        init(context);
    }

    public FilterPositionView(Context context,AttributeSet attrs) {
        super(context,attrs);
        init(context);
    }

    public FilterPositionView(Context context,AttributeSet attrs,int defStyleAttr) {
        super(context,attrs,defStyleAttr);
        init(context);
    }

    public FilterPositionView(Context context,int defStyleAttr,int defStyleRes) {
        super(context,defStyleAttr,defStyleRes);
        init(context);
    }

    private void init(Context context) {
        mBinding = DataBindingUtil.inflate(LayoutInflater.from(context),R.layout.filter_position,this,true);
        setOrientation(HORIZONTAL);

        mBinding.filterPositionCheck.setOnCheckedChangeListener((buttonView,isChecked) -> {
            mBinding.filterPositionValue.setEnabled(isChecked);
            if (!isChecked) mBinding.filterPositionValue.setText("");
        });
    }

    /**
     * Zwraca wpisywany text
     *
     * @return wpisane litery tekstu
     */
    public String getFilterValue() {
        return mBinding.filterPositionValue.getText().toString();
    }

    @BindingAdapter(value = {"bind:filterTitle","bind:filterStringValue","bind:filterDateValue"},requireAll = false)
    public static void setFilterBinding(FilterPositionView positionView,String filterTitle,String filterStringValue,Long filterDateValue) {
        positionView.mBinding.filterPositionTitle.setText(filterTitle);
        if (filterStringValue != null)
            positionView.mBinding.filterPositionValue.setText(filterStringValue);
        if (filterDateValue != null)
            positionView.mBinding.filterPositionValue.setText(DateTimeFormatUtil.format(filterDateValue));
    }

    @BindingAdapter(value = {"android:afterTextChanged","android:filterStringValuetAttrChanged"},requireAll = false)
    public static void setTextWatcher(FilterPositionView filterPositionView,final TextViewBindingAdapter.AfterTextChanged after,final InverseBindingListener textAttrChanged) {
        TextWatcher newValue = new TextWatcher() {

            @Override
            public void beforeTextChanged(CharSequence s,int start,int count,int after) {
            }

            @Override
            public void onTextChanged(CharSequence s,int before,int count) {
            }

            @Override
            public void afterTextChanged(Editable s) {
                if (after != null) {
                    after.afterTextChanged(s);
                }
                if (textAttrChanged != null) {
                    textAttrChanged.onChange();
                }
            }
        };
        TextWatcher oldValue = ListenerUtil.trackListener(filterPositionView.mBinding.filterPositionValue,newValue,R.id.textWatcher);
        if (oldValue != null) {
            filterPositionView.mBinding.filterPositionValue.removeTextChangedListener(oldValue);
        }
        filterPositionView.mBinding.filterPositionValue.addTextChangedListener(newValue);
    }
}

当然,您必须在XML布局中添加@ = {},如下所示:

<com.example.customviews.FilterPositionView
                style="@style/verticalLabeledValueStyle"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                bind:filterTitle="@{@string/filter_product}"
                bind:filterStringValue="@={sfmodel.product}"/>

以上是来客网为你收集整理的Android自定义视图和自定义Attr的双向数据绑定全部内容,希望文章能够帮你解决Android自定义视图和自定义Attr的双向数据绑定所遇到的程序开发问题。

如果觉得来客网网站内容还不错,欢迎将来客网网站推荐给程序员好友。