Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Data bindings with custom listeners on custom view

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?

like image 676
fstephany Avatar asked Sep 04 '15 15:09

fstephany


People also ask

Can I use both data binding and view binding?

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.

How do I enable data binding and view 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.

What is the advantage of using view data binding compared to using findViewById?

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.

Is view binding faster than findViewById?

Databinding is really faster compared to findViewById and setText . Not only performance, It is also much faster and maintainable for mid, full-scale projects.

How to manage callbacks with a custom listener?

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.

How do I use a custom binding target in my views?

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.

How to create reusable UI with data binding?

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.

How to handle currencycode attribute in data binding component?

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.


2 Answers

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

Yeah!! it worked

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

like image 155
subhash Avatar answered Oct 11 '22 03:10

subhash


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
    }
}
like image 8
Linh Avatar answered Oct 11 '22 04:10

Linh