2011-11-23 5 views
13

Utilizzo PagerAdapter per lo scorrimento orizzontale per la visualizzazione di pagine di giornali nella mia app.Implementazione scorrimento circolare in PagerAdapter

Attualmente voglio implementare lo scorrimento circolare in questa app. Ora quello che ho fatto è whenever I am getting on last page I try to set the currentItem to first page cioè quella funzionalità che lavora per l'ultima pagina alla prima pagina, ma il problema è che come posso andare all'ultima pagina dalla prima pagina . Qui sto incollando il mio codice relative al pagerAdapter & onPageChangeListener: -

awesomeAdapter = new AwesomePagerAdapter(awesomePager); 
    awesomePager.setAdapter(awesomeAdapter); 
    awesomePager.setPageMargin(10); 
    awesomePager.setOnPageChangeListener(new OnPageChangeListener() { 

     int lastPosition; 
     float posOffset = 0; 
     @Override 
     public void onPageSelected(int position) { 
       viewerPage = position; 
       CommonLogic.logMessage("Viewer Page:- "+ viewerPage, TAG, Log.VERBOSE); 
       posOffset = 0; 
     } 

     @Override 
     public void onPageScrolled(int position,float positionOffset,int positionOffsetPixels) { 
      if (positionOffset == 0 && positionOffsetPixels == 0 && position != 0) { 
        lastPosition = position; 
      } 

      posOffset -= positionOffset; 

      CommonLogic.logMessage(" Position:- " 
            + position + " Position Offset:- "          + positionOffset 
             + " Position Offset Variable:- " 
             + posOffset 
             + " Position Offset Pixels:- " 
             + positionOffsetPixels 
             + " Last Position " + lastPosition, 
             TAG, Log.VERBOSE); 

           CommonLogic.logMessage(" Last Position " 
             + lastPosition, TAG, Log.VERBOSE); 

     } 

     @Override 
     public void onPageScrollStateChanged(int state) { 
       // To Detect the Last Page & This Sets it to first page.This working fine. 
     if (state == ViewPager.SCROLL_STATE_DRAGGING && viewerPage == (uris.size() - 1)) { 
      CommonLogic.logMessage("Scroll State Changed ", TAG,Log.VERBOSE); 
      postDelayed(new Runnable() { 
       @Override 
       public void run() { 
       awesomePager.setCurrentItem(0, true); 
       } 
      }, 200); 
     } 
// I have also used this to detect whether the user is on first & try to move on last page,but it is not working well. 
else if (state == ViewPager.SCROLL_STATE_DRAGGING && (lastPosition == 0 || lastPosition == (uris.size() - 1)) && viewerPage == 0 && posOffset <= 0) { 
            CommonLogic.logMessage("Scroll State Changed ", TAG,Log.VERBOSE); 
    postDelayed(new Runnable() { 
     @Override 
     public void run() { 
     awesomePager.setCurrentItem((uris.size() - 1), true); 
       } 
     }, 200); 
     } 
} 
} 
    }); 

Anche il PagerAdapter cioè AwesomweAdapter nel mio caso, è anche come folllows: -

private class AwesomePagerAdapter extends PagerAdapter { 

    ViewPager pdfContainer; 
    DocumentNewView documentNewView; 
    CustomViewPager customViewPager; 

    public AwesomePagerAdapter(CustomViewPager awesomePager) { 
     this.customViewPager = awesomePager; 
    } 

    @Override 
    public int getItemPosition(Object object) { 
     return POSITION_NONE; 
    } 

    @Override 
    public int getCount() { 
     return uris.size(); 
    } 

    public DocumentNewView addViewAt(int position, DocumentNewView mainView) { 
     CommonLogic.logMessage("Position of View:- " + position, TAG, 
       Log.VERBOSE); 
     pdfContainer.addView(mainView); 
     return mainView; 
    } 

    /** 
    * Create the page for the given position. The adapter is responsible 
    * for adding the view to the container given here, although it only 
    * must ensure this is done by the time it returns from 
    * {@link #finishUpdate()}. 
    * 
    * @param container 
    *   The containing View in which the page will be shown. 
    * @param position 
    *   The page position to be instantiated. 
    * @return Returns an Object representing the new page. This does not 
    *   need to be a View, but can be some other container of the 
    *   page. 
    */ 
    @Override 
    public Object instantiateItem(View collection, int position) { 
     CommonLogic 
       .logMessage("Instantiate Item Called ", TAG, Log.VERBOSE); 

     documentNewView = new DocumentNewView(cxt, display, customViewPager); 
     documentNewView.setPdfContext(new PdfContext()); 
     CodecDocument codecDocument = documentNewView.open(uris 
       .get(position)); 
     documentNewView.renderDocument(codecDocument); 
     documentNewView.setMaxZoom(4f); 
     documentNewView.setVerticalScrollBarEnabled(true); 
     codecDocument = null; 
     this.pdfContainer = (ViewPager) collection; 
     return addViewAt(position, documentNewView); 
    } 

    /** 
    * Remove a page for the given position. The adapter is responsible for 
    * removing the view from its container, although it only must ensure 
    * this is done by the time it returns from {@link #finishUpdate()}. 
    * 
    * @param container 
    *   The containing View from which the page will be removed. 
    * @param position 
    *   The page position to be removed. 
    * @param object 
    *   The same object that was returned by 
    *   {@link #instantiateItem(View, int)}. 
    */ 
    @Override 
    public void destroyItem(View collection, int position, Object view) { 
     pdfContainer.removeView((DocumentNewView) view); 

    } 

    /** 
    * Called when the a change in the shown pages has been completed. At 
    * this point you must ensure that all of the pages have actually been 
    * added or removed from the container as appropriate. 
    * 
    * @param container 
    *   The containing View which is displaying this adapter's 
    *   page views. 
    */ 
    @Override 
    public void finishUpdate(View arg0) { 
     CommonLogic.logMessage("Finish Update Called ", TAG, Log.VERBOSE); 
    } 

    @Override 
    public void restoreState(Parcelable arg0, ClassLoader arg1) { 
    } 

    @Override 
    public Parcelable saveState() { 
     return null; 
    } 

    @Override 
    public void startUpdate(View arg0) { 
     CommonLogic.logMessage("State Update Called ", TAG, Log.VERBOSE); 
    } 

    @Override 
    public boolean isViewFromObject(View view, Object object) { 
     return view == ((DocumentNewView) object); 

    } 

Per favore mi dia eventuali suggerimenti/modifiche nel mio codice (se applicabile) per questo. Grazie in anticipo.

+0

ho visto alcuni adattatore lista circolare nella documentazione .... –

+1

tobi_b Quali documenti stai parlando riguardo è l'Android o qualcun altro. –

risposta

8

Avevo anche bisogno di un ViewPager circolare. Questo è quello che ho fatto. Presumo che tu ottenga il valore di pageCount da qualche parte.

... 
    pager = (ViewPager) findViewById(R.id.pager); 
    //Gesture detection 
    final GestureDetector gestureDetector = new GestureDetector(new MyGestureDetector()); 
    pager.setOnTouchListener(new OnTouchListener() { 
     @Override 
     public boolean onTouch(View v, MotionEvent event) { 
      return gestureDetector.onTouchEvent(event); 
     } 
    }); 

    //pagelistener is just for getting selected page 
    pager.setOnPageChangeListener(new OnPageChangeListener() { 

     @Override 
     public void onPageSelected(int position) { 
      selectedPage = position; 
     } 

     @Override 
     public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { 
     } 

     @Override 
     public void onPageScrollStateChanged(int state) { 
     } 
    }); 

e qui è il GestureDetector. copiato da here

class MyGestureDetector extends SimpleOnGestureListener { 

    @Override 
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { 

     int SWIPE_MIN_DISTANCE = Utils.ConvertToPixel(mContext, 50); 
     int SWIPE_MAX_OFF_PATH = Utils.ConvertToPixel(mContext, 250); 
     int SWIPE_THRESHOLD_VELOCITY = Utils.ConvertToPixel(mContext, 200); 

     try { 

      if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH) 
       return false; 
      // right to left swipe 
      if(e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE 
        && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY 
        && selectedPage == (pageCount - 1)) { 
       pager.setCurrentItem(0); 
       return true; 
      } else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE 
        && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY 
        && selectedPage == 0) { 
       pager.setCurrentItem(pageCount - 1); 
       return true; 
      } 
     } catch (Exception e) { 
      // nothing 
     } 
     return false; 
    } 

} 
+0

: - Grazie per la risposta. Proverò questa cosa e ti risponderò presto. –

+0

@efeyc grazie !! pager.setOnTouchListener (..) ha risolto tutti i miei problemi! – Beppe

+0

@efeyc ** MotionEvent e1 è sempre nullo in onFling() **. Può essere a causa della visualizzazione dello swipe dell'implementazione del cercapersone. Non hai affrontato questo problema? –

20

ho potuto realizzare questo ridefinendo onPageSelected metodo OnPageChangeListener. Considera di avere tre pagine nell'ordine A<->B<->C. L'obiettivo è raggiungere C se scorgiamo a destra da A e allo stesso modo raggiungere lo A se scendiamo a sinistra da C.

A tale scopo, definire il vostro avere 5 pagine (3 + 2), e organizzare le pagine come segue:

C<->A<->B<->C<->A

Ora nel metodo onPageSelected, controllare e se la posizione è 0, modificarla in 3 (getCount()-2) e se la posizione è 4 (getCount()-1), modificarla in 1. Assicurarsi di utilizzare il metodo:

setCurrentItem(item, smoothScroll) 

Ecco il codice completo per CircularPagerAdaptor Classe:

package zolender.adapters; 

import android.content.Context; 
import android.os.Parcelable; 
import android.support.v4.view.PagerAdapter; 
import android.support.v4.view.ViewPager; 
import android.support.v4.view.ViewPager.OnPageChangeListener; 
import android.view.LayoutInflater; 
import android.view.View; 

public class CircularPagerAdapter extends PagerAdapter{ 

    private int[] pageIDsArray; 
    private int count; 

    public CircularPagerAdapter(final ViewPager pager, int... pageIDs) { 
     super(); 
     int actualNoOfIDs = pageIDs.length; 
     count = actualNoOfIDs + 2; 
     pageIDsArray = new int[count]; 
     for (int i = 0; i < actualNoOfIDs; i++) { 
      pageIDsArray[i + 1] = pageIDs[i]; 
     } 
     pageIDsArray[0] = pageIDs[actualNoOfIDs - 1]; 
     pageIDsArray[count - 1] = pageIDs[0]; 

     pager.setOnPageChangeListener(new OnPageChangeListener() { 

      @Override 
      public void onPageSelected(int position) { 
       int pageCount = getCount(); 
       if (position == 0){ 
        pager.setCurrentItem(pageCount-2,false); 
       } else if (position == pageCount-1){ 
        pager.setCurrentItem(1,false); 
       } 
      } 

      @Override 
      public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { 
       // TODO Auto-generated method stub 
      } 

      @Override 
      public void onPageScrollStateChanged(int state) { 
       // TODO Auto-generated method stub 
      } 
     }); 
    } 

    public int getCount() { 
     return count; 
    } 

    public Object instantiateItem(View container, int position) { 
     LayoutInflater inflater = (LayoutInflater) container.getContext() 
       .getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
     int pageId = pageIDsArray[position]; 
     View view = inflater.inflate(pageId, null); 
     ((ViewPager) container).addView(view, 0); 
     return view; 
    } 

    @Override 
    public void destroyItem(View container, int position, Object object) { 
     ((ViewPager) container).removeView((View) object); 
    } 

    @Override 
    public void finishUpdate(View container) { 
     // TODO Auto-generated method stub 
    } 

    @Override 
    public boolean isViewFromObject(View view, Object object) { 
     return view == ((View) object); 
    } 

    @Override 
    public void restoreState(Parcelable state, ClassLoader loader) { 
     // TODO Auto-generated method stub 
    } 

    @Override 
    public Parcelable saveState() { 
     // TODO Auto-generated method stub 
     return null; 
    } 

    @Override 
    public void startUpdate(View container) { 
     // TODO Auto-generated method stub 
    } 
} 

Ed ecco come si può utilizzare:

myPager = (ViewPager) findViewById(R.id.myfivepanelpager); 
PagerAdapter adapter = new CircularPagerAdapter(myPager, new int[]{R.layout.farleft, R.layout.left, R.layout.middle, R.layout.right, R.layout.farright}); 
myPager.setAdapter(adapter); 
myPager.setCurrentItem(3); 
+0

hey puoi spiegarlo in modo più preciso, lo ha provato ma non ha funzionato. – krisDrOid

+2

quale parte era confusa? In poche parole, aggiungo due pagine fittizie in entrambe le direzioni e, quando sono selezionate, ho spostato la selezione nella sua posizione attuale. – Z0lenDer

+0

Grazie mille !!!!!!! – Chaitu

4

Ampliando Z0lenDer la risposta, quando si utilizza un normale ViewPager in cui non è necessario liberare la memoria per ogni vista associata, è più efficiente memorizzare le viste create anziché gli ID di layout. Questo è necessario se si vuole eliminare ogni ritardo e sfarfallio quando si cambia l'oggetto.

C'è anche un problema con l'animazione quando si utilizza onPageSelected, in quanto non lascia la finitura della diapositiva prima di fare lo switch.L'unico modo che ho trovato per evitare questo è quello di eseguire l'interruttore solo una volta che lo stato di scorrimento è stato modificato in SCROLL_STATE_IDLE e semplicemente impostando l'elemento corrente in onPageSelected.

private int currentPage = 0; 

...

pager.setOnPageChangeListener(new OnPageChangeListener() { 

     @Override 
     public void onPageSelected(int position) { 
      currentPage = position; 
     } 

     @Override 
     public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { 

     } 

     @Override 
     public void onPageScrollStateChanged(int state) { 
      // TODO Auto-generated method stub 
      Log.d(TAG, "onPageScrollStateChanged: " + state); 
      if (state == ViewPager.SCROLL_STATE_IDLE) { 
       int pageCount = getCount(); 
       if (currentPage == 0){ 
        pager.setCurrentItem(pageCount-2,false); 
       } else if (currentPage == pageCount-1){ 
        pager.setCurrentItem(1,false); 
       } 
      } 
     } 

    }); 
0

Prova questo

((ViewPager) container) 
       .setOnPageChangeListener(new OnPageChangeListener() { 
        @Override 
        public void onPageSelected(int position) { 
         Log.i("TAG", "pos::" + position); 

        } 
        @Override 
        public void onPageScrollStateChanged(int state) { 
         // TODO Auto-generated method stub        
          int currentPage = pager.getCurrentItem(); 
          Log.i("TAG", "currentPage::" + currentPage); 
          Log.i("TAG", "currentState::" + currentState); 
          Log.i("TAG", "previousState::" + previousState); 
          if (currentPage == 4 || currentPage == 0) { 
          previousState = currentState; 
          currentState = state; 
          if (previousState == 1 && currentState == 0) { 
          pager.setCurrentItem(currentPage == 0 ? 4 : 0); 
          } 
          } 

        } 

        @Override 
        public void onPageScrolled(int arg0, float arg1, 
          int arg2) { 
         // TODO Auto-generated method stub 

        } 
       }); 

     return 

Questo dovrebbe essere collocato all'interno

@Override 
    public Object instantiateItem(final View container, int position) {} 
0

ho usato in questo modo, layout frammento in adattatore 0 > 1> 2> 3> 4> 5, 5 sono fittizio

viewPager.setAdapter(adapter); 
    viewPager.setCurrentItem(1, false);  //going to page 1; 

    final int[] pagePosition = new int[1]; 

    viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { 
     @Override 
     public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { 

     } 

     @Override 
     public void onPageSelected(int position) { 
      pagePosition[0] = position; 
     } 

     @Override 
     public void onPageScrollStateChanged(int state) { //state changes from 2 to 0 during a swipe 

      if (state == 0 && pagePosition[0] == 0){    
       viewPager.setCurrentItem(4, false); 
      } else if (state == 0 && pagePosition[0] == 5){ 
       viewPager.setCurrentItem(1, false); 
      } 
     } 
    }); 
0

Ebbene questo ha aiutato

private class CircularViewPagerHandler implements ViewPager.OnPageChangeListener { 
    private ViewPager mViewPager; 
    private int mCurrentPosition; 
    private int mScrollState; 
    private int mPreviousPosition; 

    public CircularViewPagerHandler(final ViewPager viewPager) { 
     mViewPager = viewPager; 
    } 

    @Override 
    public void onPageSelected(final int position) { 
     mCurrentPosition = position; 
     mPreviousPosition = position-1; 
    } 

    @Override 
    public void onPageScrollStateChanged(final int state) { 
     if (state == ViewPager.SCROLL_STATE_IDLE) { 
      setNextItemIfNeeded(); 
     } 
     mScrollState = state; 
    } 


    private void setNextItemIfNeeded() { 
     if (!isScrollStateSettling()) { 
      handleSetNextItem(); 
     } 
    } 

    private boolean isScrollStateSettling() { 
     return mScrollState == ViewPager.SCROLL_STATE_SETTLING; //indicated page is settling to it's final position 
    } 

    private void handleSetNextItem() { 
     final int lastPosition = mViewPager.getAdapter().getCount() - 1; 
     if (mCurrentPosition == 0) { 
      mViewPager.setCurrentItem(lastPosition,false); 
     } else if (mCurrentPosition == lastPosition) { 
      mViewPager.setCurrentItem(0, false); 
     } 
    } 

    @Override 
    public void onPageScrolled(final int position, final float positionOffset, final int positionOffsetPixels) { 

    } 
} 

E 'stato di @answer