2016-08-02 26 views
5

Ich habe 2-Wege-Databinding für eine grundlegende Anwendung verwendet, es lief ziemlich gut, bis ich mit benutzerdefinierten Ansichten und attrs beginne.Android 2-Way DataBinding mit benutzerdefinierter Ansicht und benutzerdefiniertem Attr

Ich möchte eine benutzerdefinierte Ansicht erstellen, mit einem Textview und eine EditText, und verwenden Sie es in einem anderen Layout:

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

und ich habe die Gewohnheit attr für sie

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

im Fragment i Sie wie folgt vor:

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

Es ist schön hat 1-Wege databind funktioniert, aber was auch immer ich den Text zu ändern, er mir nicht den Rückruf in der Klasse senden

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

Wer weiß, wie es richtig funktioniert?

Fully kann Code bei here

Antwort

7

Dies funktioniert für mich zu finden:

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

Natürlich hinzufügen müssen @={} wie unten in der XML-Layouts:

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