Android 自定义组件的双向数据绑定?
Android two way data binding for custom component?
我正在尝试关注 this 博客 post 以尝试获得两种方式的数据绑定以用于自定义组件(其中包含 EditText 的约束视图)。
我能够让两个标准的 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";
}
}
Activity:
@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);
}
我认为 post 中的 "Hooking The Event" 部分完全超出了我的理解;我真的只需要一个简单的 setter 和 getter 作为组件,所以不太明白那个 BindingAdapter 做了什么。在所有这些中,我认为这是我根本不了解的这一行:
ValueChangeListener oldListener =
ListenerUtil.trackListener(view, newListener,
R.id.textWatcher);
抱歉,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()
并且你不需要 removeListener()
因为你总是可以将侦听器设置为 null
.
您遇到的问题出在您的组件中:
public String getValue() {
return value;
}
您返回的是 setter 上次设置的值,而不是 EditText 中的值。要解决这个问题:
public String getValue() {
return txt.getText().toString();
}
我正在尝试关注 this 博客 post 以尝试获得两种方式的数据绑定以用于自定义组件(其中包含 EditText 的约束视图)。
我能够让两个标准的 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";
}
}
Activity:
@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);
}
我认为 post 中的 "Hooking The Event" 部分完全超出了我的理解;我真的只需要一个简单的 setter 和 getter 作为组件,所以不太明白那个 BindingAdapter 做了什么。在所有这些中,我认为这是我根本不了解的这一行:
ValueChangeListener oldListener =
ListenerUtil.trackListener(view, newListener,
R.id.textWatcher);
抱歉,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()
并且你不需要 removeListener()
因为你总是可以将侦听器设置为 null
.
您遇到的问题出在您的组件中:
public String getValue() {
return value;
}
您返回的是 setter 上次设置的值,而不是 EditText 中的值。要解决这个问题:
public String getValue() {
return txt.getText().toString();
}