我一直在为基本应用程序使用双向数据绑定,它很顺利,直到我开始使用自定义视图和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); } }
有谁知道如何让它正常工作?
解决方法
这对我有用:
@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}"/>