I'm trying to bind an event on a custom view with the new Android data-binding library but run into an issue.
Here's the relevant part of my custom view:
public class SuperCustomView extends FrameLayout {
private OnToggleListener mToggleListener;
public interface OnToggleListener {
void onToggle(boolean switchPosition);
}
public void setOnToggleListener(OnToggleListener listener) {
mToggleListener = listener;
}
.../...
}
I'm trying to use this Custom View and bind the onToggle
event with the following:
<data>
<variable
name="controller"
type="com.xxx.BlopController"/>
</data>
<com.company.views.SuperCustomView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:onToggle="@{controller.toggleStrokeLimitation}"
app:custom_title="Blah"
app:custom_summary="Bloh"
app:custom_widget="toggle"/>
Where toggleStrokeLimitation
is a method on the controller:
public void toggleStrokeLimitation(boolean switchPosition) {
maxStrokeEnabled.set(switchPosition);
}
I get this error when compiling:
> java.lang.RuntimeException: Found data binding errors.
****/ data binding error ****msg:Cannot find the setter for attribute 'app:onToggle' with parameter type java.lang.Object. file:/path/to/androidapp/app/src/main/res/layout/fragment_stroke.xml loc:36:35 - 36:67 ****\ data binding error ****
I've tried to use android:onToggle
instead of app:onToggle
but get the same error.
When reading the binding events section of the doc, I feel like I can wire any method off the controller to the onToggle
event.
Does the framework wrap the controller.toggleStrokeLimitation
methods into a SuperCustomView.OnToggleListener
? Any hint on the kind of magic that is behind the existing onClick
provided by the framework?
View binding doesn't support layout variables or layout expressions, so it can't be used to declare dynamic UI content straight from XML layout files. View binding doesn't support two-way data binding.
Step 2: Enabling the ViewBinding Feature There is a need to enabling the ViewBinding feature in Android Studio 4.0 and above, inside the app-level build gradle file. Invoke the following code snippet inside the android{} body of the gradle file.
View binding replaces findViewById with a concise, safe alternative. Type-safe because properties are always correctly typed based on the views in the layout. So if you put a TextView in the layout, view binding will expose a TextView property. Null-safe for layouts defined in multiple configurations.
Databinding is really faster compared to findViewById and setText . Not only performance, It is also much faster and maintainable for mid, full-scale projects.
There are four steps to using a custom listener to manage callbacks in your code: Define an interface as an event contract with methods that define events and arguments which are relevant event data. Setup a listener member variable and setter in the child object which can be assigned an implementation of the interface.
Once you have registered a custom binding target, you can use it in your views as follows: If you do not wish to specify For ("MyProperty") you can setup a default binding name in your Setup class. You can learn more about this here.
You usually end up with a custom view with a lot of boiler plate code or nested fragments with complex life cycles. A really simple way to deal with this problem is to use data binding to create little pieces of reusable UI. We only need to write code in the XML and the communication with the component is made by the bindings.
But if you want to use your custom view with data binding component actually you don’t need to handle this attributes. data binding library has automatic method selection ability, that means for an attribute named currencyCode, the library automatically tries to find the method setCurrencyCode (arg) that accepts compatible types as the argument.
@BindingMethods(@BindingMethod(type = SuperCustomView.class, attribute = "app:onToggle", method = "setOnToggleListener"))
public class SuperCustomView extends FrameLayout {
private OnToggleListener mToggleListener;
public interface OnToggleListener {
void onToggle(boolean switchPosition);
}
public void setOnToggleListener(OnToggleListener listener) {
mToggleListener = listener;
}
.../...
}
My hack to test code was:
public void setOnToggleListener(final OnToggleListener listener) {
this.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
toggle = !toggle;
listener.onToggle(toggle);
}
});
}
And on my controller object:
public class MyController {
private Context context;
public MyController(Context context) {
this.context = context;
}
public void toggleStrokeLimitation(boolean switchPosition) {
Toast.makeText(context, "Toggle" + switchPosition, Toast.LENGTH_SHORT).show();
}
}
Alternatively you can use xml like:
<com.androidbolts.databindingsample.model.SuperCustomView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:onToggleListener="@{controller.toggleStrokeLimitation}" />
Now no need to add @BindingMethods annotation.
Documentation says: "Some attributes have setters that don't match by name. For these methods, an attribute may be associated with the setter through BindingMethods annotation. This must be associated with a class and contains BindingMethod annotations, one for each renamed method. "
You may not need BindingMethods
for listen listeners on custom view if you define method name follow Java bean format CORRECTLY.
Here is an example
CustomView class
public class CustomView extends LinearLayout {
...
private OnCustomViewListener onCustomViewListener;
...
public void setOnCustomViewListener(OnCustomViewListener onCustomViewListener) {
this.onCustomViewListener = onCustomViewListener;
}
....
public interface OnCustomViewListener {
void onCustomViewListenerMethod(int aNumber);
}
}
XML
<...CustomView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:onCustomViewListener="@{viewModel.viewModelListenerMethod}" // or use can use app:onCustomViewListener="@{viewModel::viewModelListenerMethod}"
/>
ViewModel
public class ViewModel extends BaseObservable{
public void viewModelListenerMethod(int aNumber){
// handle listener here
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With