2016-06-03 2 views
5

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

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

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

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

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

Ошибка: (6 2) Идентификатор ресурса не найден для атрибута 'onPageChangeListener' в пакете 'android'

ответ

7

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

Для того, чтобы реализовать пользовательский адаптер, вы можете прочитать this.

Код должен быть что-то вроде ниже, я не проверял их тщательно:

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

P.S. Пропущенный класс обработчика должен содержать ViewPager.OnPageChangeListener.

+1

Не очень хорошее решение. Поскольку ViewPager добавляет OnPageChangeListener к внутреннему ArrayList, вызов notifyChange() для этого свойства заставит его добавить несколько слушателей. – b1n0m

+0

@ b1n0m обновлено, чтобы удалить слушателей, прежде чем добавлять слушателя –

3

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

@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 будет иметь возможность установить текущую страницу, а также получить ток если пользователь выполняет поиск.

+0

Эти параметры позволяют динамически обновлять фрагмент в viewpager? в настоящее время? –

+0

@ azizi-musa, вы можете установить значение 'viewModel.currentPage', чтобы выбрать другую страницу. Если вы хотите изменить фрагменты в 'ViewPager', вы должны сделать это в' PagerAdapter'. – b1n0m

Смежные вопросы