2016-08-02 23 views
5

Tôi đã sử dụng dữ liệu 2 chiều cho một ứng dụng cơ bản, nó đã được thực hiện khá tốt, cho đến khi tôi bắt đầu với quan điểm tùy chỉnh và attrs.Android 2-Way DataBinding với Custom View và Custom Attr

Tôi muốn tạo ra một cái nhìn tùy chỉnh, với có một TextView và một EditText, và sử dụng nó bên trong bố trí khác:

<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" /> 

Và tôi có attr tùy chỉnh cho nó

<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> 

Trong đoạn tôi làm như sau:

<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:" /> 
.210

Nó hoạt động tốt có 1 chiều DataBind, nhưng bất cứ điều gì tôi thay đổi các văn bản, ông không gửi cho tôi gọi lại trong lớp

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

Có ai biết làm thế nào để làm cho nó hoạt động đúng?

đầy đủ mã có thể được tìm thấy tại here

Trả lời

7

này làm việc cho tôi:

@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, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 
     super(context, attrs, 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 start, 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); 
    } 
} 

Tất nhiên Bạn phải thêm @={} trong bố trí XML của bạn như dưới đây:

<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}"/>