2016-06-03 23 views
5

È possibile associare un gestore per setOnPageChangeListener a un ViewPager in file XML con la funzionalità Android Binding?Associazione dati evento Android Binding per ViewPager

Le demo mostrano eventi onClick ma sono curioso di sapere quanta funzionalità di evento posso implementare con esso. Sarebbe fantastico anche qualsiasi link sulle funzionalità di Data Binding. Grazie.

Esempio ipotetico:

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

L'errore di compilazione è:

Errore: (6 2) Nessun identificatore di risorsa trovato per l'attributo 'onPageChangeListener' nel pacchetto 'android'

risposta

7

È possibile farlo. È necessario implementare un adattatore di associazione personalizzato poiché non esistono classi BindingAdapter predefinite per le classi Visualizza dalle librerie di supporto Android.

Per come implementare l'adattatore personalizzato è possibile leggere this.

Il codice dovrebbe essere qualcosa di simile al di sotto, non li ho testato a fondo:

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

Il codice 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. La classe di gestore che viene passata deve implementare ViewPager.OnPageChangeListener.

+1

Soluzione non buona. Poiché ViewPager aggiunge OnPageChangeListener a ArrayList interno, la chiamata a notifyChange() per questa proprietà consente di aggiungere più listener. – b1n0m

+0

@ b1n0m aggiornato per rimuovere gli ascoltatori prima di aggiungere listener –

3

Ecco la soluzione definitiva. Metti solo questa lezione nel tuo progetto.

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

Aggiungere anche la risorsa id nelle risorse.

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

Allora si sarà in grado di usarlo in XML come:

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

Come si può vedere, currentPage ha inversa vincolante, così il vostro ViewModel sarà in grado di impostare la pagina corrente e anche corrente ottenere pagina se l'utente fa scorrere.

+0

queste impostazioni sono in grado di aggiornare il frammento in viewpager in modo dinamico? in tempo reale? –

+0

@ azizi-musa, è possibile impostare il valore 'viewModel.currentPage' per selezionare un'altra pagina. Se vuoi cambiare i frammenti in 'ViewPager', dovresti farlo in' PagerAdapter'. – b1n0m

Problemi correlati