Привязка данных для прослушивателя событий Android для ViewPager

Можно ли привязать обработчик для setOnPageChangeListener к ViewPager в XML-файле с функцией привязки Android?

Демонстрации показывают события onClick, но мне любопытно, какую функциональность событий я могу реализовать с его помощью. Любые ссылки на возможности Data Binding будут также хороши. Благодарю.

Гипотетический пример:

example_activity.xml

<?xml version,="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">

<data>
   <variable name="handlers" type="com.example.Handlers"/>
</data>

<android.support.v4.view.ViewPager
    android:id="@+id/pager"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"

    android:onPageChangeListener="@{handlers.pageChanged}" />
</layout>

Handler.java

package com.example.viewmodels;

import android.view.View;

public class Handlers {
    public void pageChanged(View view){}
}

Ошибка компиляции:

Ошибка: (62) Не найден идентификатор ресурса для атрибута «onPageChangeListener» в пакете «android»

Ответы на вопрос(2)

Решение Вопроса

привязки, потому что нет классов BindingAdapter, предопределенных для классов View из библиотек поддержки Android.

О том, как реализовать пользовательский адаптер, вы можете прочитатьэтот.

Код должен быть примерно таким, как показано ниже, я не проверил их полностью:

<android.support.v4.view.ViewPager
    android:id="@+id/pager"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:onPageChangeListener="@{handlers}" />

Ваш код BindingAapter:

@BindingAdapter("onPageChangeListener")
public static void setOnPageChangeListener(ViewPager viewPager, ViewPager.OnPageChangeListener listener) {
    Log.i("setOnPageChangeListener");

    // clear listeners first avoid adding duplicate listener upon calling notify update related code
    viewPager.clearOnPageChangeListeners();
    viewPager.addOnPageChangeListener(listener);
}

Постскриптум Ваш передаваемый класс обработчика должен реализоватьViewPager.OnPageChangeListener.

 mr.icetea01 июн. 2018 г., 11:41
@DavidCheung, если у меня естьPageIndicator.setPager(viewpager), Как я могу связатьviewpager кindicator
 Siddhivinayak17 апр. 2018 г., 10:35
@ Дэвид Чунг, мой слушатель возвращает ноль, когда я отлаживаю приложение. Есть идеи, почему это может происходить?
 b1n0m08 июн. 2017 г., 10:39
Не хорошее решение. Поскольку ViewPager добавляет OnPageChangeListener к внутреннему ArrayList, вызов notifyChange () для этого свойства заставит его добавить несколько прослушивателей.
 David Cheung08 июн. 2017 г., 10:42
Обновление @ b1n0m для удаления слушателей перед добавлением слушателя

Вот окончательное решение. Просто поместите этот класс в свой проект.

@BindingMethods({
    @BindingMethod(type = ViewPager.class, attribute = "android:offscreenPageLimit", method = "setOffscreenPageLimit"),
    @BindingMethod(type = ViewPager.class, attribute = "android:adapter", method = "setAdapter"),
    @BindingMethod(type = ViewPager.class, attribute = "android:currentPage", method = "setCurrentItem"),
})
public final class ViewPagerBindingAdapter {

    @InverseBindingAdapter(attribute = "android:currentPage", event = "android:currentPageAttrChanged")
    public static int getCurrentPage(@NonNull final ViewPager pager) {
        return pager.getCurrentItem();
    }

    @BindingAdapter(value = {"android:onPageScrolled", "android:onPageSelected", "android:onPageScrollStateChanged",
        "android:currentPageAttrChanged"}, requireAll = false)
    public static void onSetAdapter(@NonNull final ViewPager pager, final OnPageScrolled scrolled, final OnPageSelected selected,
        final OnPageScrollStateChanged scrollStateChanged, final InverseBindingListener currentPageAttrChanged) {

        final ViewPager.OnPageChangeListener newValue;
        if (scrolled == null && selected == null && scrollStateChanged == null && currentPageAttrChanged == null) {
            newValue = null;
        } else {
            newValue = new ViewPager.OnPageChangeListener() {
                @Override
                public void onPageScrolled(final int position, final float positionOffset, final int positionOffsetPixels) {
                    if (scrolled != null) {
                        scrolled.onPageScrolled(position, positionOffset, positionOffsetPixels);
                    }
                }

                @Override
                public void onPageSelected(final int position) {
                    if (selected != null) {
                        selected.onPageSelected(position);
                    }
                    if (currentPageAttrChanged != null) {
                        currentPageAttrChanged.onChange();
                    }
                }

                @Override
                public void onPageScrollStateChanged(final int state) {
                    if (scrollStateChanged != null) {
                        scrollStateChanged.onPageScrollStateChanged(state);
                    }
                }
            };
        }
        final ViewPager.OnPageChangeListener oldValue = ListenerUtil.trackListener(pager, newValue, R.id.page_change_listener);
        if (oldValue != null) {
            pager.removeOnPageChangeListener(oldValue);
        }
        if (newValue != null) {
            pager.addOnPageChangeListener(newValue);
        }
    }

    public interface OnPageScrolled {
        void onPageScrolled(int position, float positionOffset, int positionOffsetPixels);
    }

    public interface OnPageSelected {
        void onPageSelected(int position);
    }

    public interface OnPageScrollStateChanged {
        void onPageScrollStateChanged(int state);
    }

    private ViewPagerBindingAdapter() {
        throw new UnsupportedOperationException();
    }
}

Также добавьте ресурс id в ваши ресурсы.

<resources>
    <item name="page_change_listener" type="id"/>
</resources>

Тогда вы сможете использовать его в XML как:

<android.support.v4.view.ViewPager
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:currentPage="@={viewModel.currentPage}"
                android:offscreenPageLimit="@{viewModel.offscreenPageLimit}"
                android:onPageSelected="@{currentPage -> viewModel.pageSelected(currentPage)}"
                android:adapter="@{adapter}"/>

Как вы видете,currentPage имеет обратную привязку, так что ваш viewModel сможет установить текущую страницу, а также получить текущую страницу, если пользователь проводит пальцем.

 b1n0m08 нояб. 2017 г., 12:29
@ azizi-musa, вы можете установитьviewModel.currentPage значение, чтобы выбрать другую страницу. Если вы хотите изменить фрагменты вViewPagerВы должны сделать это вPagerAdapter.
 Azizi Musa12 окт. 2017 г., 09:34
Могут ли эти настройки динамически обновлять фрагмент в viewpager? в настоящее время?

Ваш ответ на вопрос