0

私は、カスタムコンポーネント(EditTextを含む制約ビュー)のために双方向データバインディングを試してみるために、thisブログポストに従っています。カスタムコンポーネントのAndroid双方向データバインディング?

2つの標準のEditTextコンポーネントをモデルと同期させることができますが、カスタムコンポーネントの変更を自分のモデルに流すのは難しいです(片方向のデータバインディング作品)。

マイモデル:

public class Model extends BaseObservable { 
    private String value; 

    @Bindable 
    public String getValue() { 
     return value; 
    } 

    public void setValue(String value) { 
     this.value = value; 
     notifyPropertyChanged(company.com.databinding.BR.value); 
    } 

    public Model() { 
     value = "Value"; 
    } 
} 

活動:

@InverseBindingMethods({ 
     @InverseBindingMethod(
       type = CustomComponent.class, 
       attribute = "value", 
       method = "getValue") 
}) 
public class MainActivity extends AppCompatActivity { 
    @BindingAdapter("value") 
    public static void setColor(CustomComponent view, String value) { 
     if (!value.equals(view.getValue())) { 
      view.setValue(value); 
     } 
    } 

    @BindingAdapter(
      value = {"onValueChange", "valueAttrChanged"}, 
      requireAll = false 
    ) 
    public static void setListeners(CustomComponent view, 
            final ValueChangeListener onValueChangeListener, 
            final InverseBindingListener inverseBindingListener) { 
     ValueChangeListener newListener; 
     if (inverseBindingListener == null) { 
      newListener = onValueChangeListener; 
     } else { 
      newListener = new ValueChangeListener() { 
       @Override 
       public void onValueChange(CustomComponent view, 
              String value) { 
        if (onValueChangeListener != null) { 
         onValueChangeListener.onValueChange(view, 
           value); 
        } 
        inverseBindingListener.onChange(); 
       } 
      }; 
     } 

     ValueChangeListener oldListener = 
       ListenerUtil.trackListener(view, newListener, 
         R.id.textWatcher); 

     if (oldListener != null) { 
      view.removeListener(oldListener); 
     } 
     if (newListener != null) { 
      view.addListener(newListener); 
     } 
    } 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     //setContentView(R.layout.activity_main); 
     ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main); 
     binding.setModel(new Model()); 
    } 
} 

カスタムコンポーネント:

public class CustomComponent extends ConstraintLayout { 
    private String value; 
    private EditText txt; 
    private TextWatcher textWatcher; 
    ValueChangeListener listener; 

    public String getValue() { 
     return value; 
    } 

    public void setValue(String value) { 
     this.value = value; 
     if (txt != null) { 
      txt.setText(value); 
     } 
    } 

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

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

    public CustomComponent(Context context, AttributeSet attrs, int defStyle) { 
     super(context, attrs, defStyle); 
     init(context, attrs); 
    } 

    private void init(Context context) { 

    } 

    private void init(Context context, AttributeSet attrs) { 
     View.inflate(context, R.layout.custom_component, this); 
     txt = findViewById(R.id.txt_box); 
     final CustomComponent self = this; 
     textWatcher = 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) { 
       if (listener != null) { 
        listener.onValueChange(self, editable.toString()); 
       } 
      } 
     }; 
     txt.addTextChangedListener(textWatcher); 
    } 

    public void addListener(ValueChangeListener listener) { 
     this.listener = listener; 
    } 

    public void removeListener(ValueChangeListener listener) { 
     this.listener = null; 
    } 
} 

public interface ValueChangeListener { 
    public void onValueChange(CustomComponent view, String value); 
} 

私はその記事では、 "イベントをフックする" セクションには、私の上に完全になくなっていると思います頭;私は実際にはコンポーネントのための単純なセッターとゲッターしか必要としませんでした。そのため、BindingAdapterで何が行われているのかは分かりませんでした。

ValueChangeListener oldListener = 
      ListenerUtil.trackListener(view, newListener, 
        R.id.textWatcher); 

デモで:https://github.com/indgov/data_binding

答えて

1

ListenerUtilが混乱したことを申し訳ありませんが、それらのすべての私はそれは私がすべてで得ることはありません。このラインだと思います。コンポーネントが複数のリスナーをサポートしている場合にのみ便利です。その場合は、新しいリスナーを設定するだけではなく、古いリスナーを削除して新しいリスナーを追加する必要があります。 ListenerUtilは、古いリスナーを追跡して削除できるようにします。あなたのケースでは、それを簡略化することができます。

@BindingAdapter(
     value = {"onValueChange", "valueAttrChanged"}, 
     requireAll = false 
) 
public static void setListeners(CustomComponent view, 
           final ValueChangeListener onValueChangeListener, 
           final InverseBindingListener inverseBindingListener) { 
    ValueChangeListener newListener; 
    if (inverseBindingListener == null) { 
     newListener = onValueChangeListener; 
    } else { 
     newListener = new ValueChangeListener() { 
      @Override 
      public void onValueChange(CustomComponent view, 
             String value) { 
       if (onValueChangeListener != null) { 
        onValueChangeListener.onValueChange(view, 
          value); 
       } 
       inverseBindingListener.onChange(); 
      } 
     }; 
    } 

    view.setListener(newListener); 
} 

、その後はsetListener()addListener()を交換し、あなたは常にnullにリスナーを設定することができますので、あなたはremoveListener()は必要ありません。

あなたが見ている問題は、あなたのコンポーネントである:

public String getValue() { 
    return value; 
} 

あなたが最後のセッターとないのEditTextにある値によって設定された値を返します。これを解決するには:

public String getValue() { 
    return txt.getText().toString(); 
} 
関連する問題