Связывание данных с пользовательскими слушателями на пользовательском представлении

Я пытаюсь связать событие на пользовательском представлении с новой библиотекой привязки данных Android, но столкнулся с проблемой.

Здесь соответствующая часть моего пользовательского представления:

public class SuperCustomView extends FrameLayout {
    private OnToggleListener mToggleListener;

    public interface OnToggleListener {
        void onToggle(boolean switchPosition);
    }

    public void setOnToggleListener(OnToggleListener listener) {
        mToggleListener = listener;
    }
    .../...
 }

Я пытаюсь использовать этот пользовательский вид и связывать событие onToggle со следующим:

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

Где toggleStrokeLimitation - это метод на контроллере:

public void toggleStrokeLimitation(boolean switchPosition) {
    maxStrokeEnabled.set(switchPosition);
}

Я получаю эту ошибку при компиляции:

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

Я попытался использовать android:onToggle вместо app:onToggle, но получаю ту же ошибку.

При чтении раздела событий привязки документа doc я чувствую, что могу подключить любой метод от контроллера к событию onToggle.

Ободряет ли оболочка методы controller.toggleStrokeLimitation в SuperCustomView.OnToggleListener? Любой намек на волшебство, которое стоит за существующим onClick, предоставленным каркасом?

Ответы

Ответ 1

@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;
    }
    .../...
}

Мой взломанный код для проверки был:

public void setOnToggleListener(final OnToggleListener listener) {
    this.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            toggle = !toggle;
            listener.onToggle(toggle);
        }
    });
}

И на моем объекте контроллера:

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

Да!! он работал

В качестве альтернативы вы можете использовать xml, например:

 <com.androidbolts.databindingsample.model.SuperCustomView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:onToggleListener="@{controller.toggleStrokeLimitation}" />

Теперь не нужно добавлять аннотацию @BindingMethods.

Документация говорит: Некоторые атрибуты имеют сеттеры, которые не совпадают по имени. Для этих методов атрибут может быть связан с установщиком с помощью аннотации BindingMethods. Это должно быть связано с классом и содержит аннотации BindingMethod, по одному для каждого переименованного метода.

Ответ 2

Вам может не понадобиться BindingMethods для прослушивания прослушивателей на пользовательском представлении, если вы определяете имя метода, следуя за форматом Java bean ПРАВИЛЬНО. Вот пример

Класс CustomView

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