2011-11-23 11 views
13

Używam PagerAdapter do przesuwania w poziomie do wyświetlania stron gazet w mojej aplikacji.Implementowanie przewijania kołowego w PagerAdapterie

Obecnie chcę zaimplementować cykliczne przewijanie w tej aplikacji. To, co zrobiłem teraz, to whenever I am getting on last page I try to set the currentItem to first page czyli funkcjonalność działająca na ostatniej stronie do pierwszej strony, ale problem polega na tym, jak mogę przejść do ostatniej strony z pierwszej strony . Oto jestem wklejając mój kod związany 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); 
     } 
} 
} 
    }); 

Również tj AwesomweAdapter PagerAdapter w moim przypadku, to także 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); 

    } 

Proszę dać mi jakieś sugestie/zmiany w moim kodzie (jeśli dotyczy) dla niego. Dzięki z góry.

+0

Widziałem jakąś okrągłą listy adapter w docs .... –

+1

Które docs mówisz o to jest Android lub inny. –

Odpowiedz

8

Potrzebowałem również okrągłego ViewPagera. Oto, co zrobiłem. Zakładam, że masz gdzieś wartość pageCount.

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

i tutaj jest gest GestureDetector. skopiowane z 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

: - Dziękuję za odpowiedź. Wypróbuję to i wkrótce odpowiem. –

+0

@efeyc thanks !! pager.setOnTouchListener (..) rozwiązał wszystkie moje problemy! – Beppe

+0

@efeyc ** MotionEvent e1 ma zawsze wartość null w onFling() **. Może być z powodu własnej implementacji przeciągania widoku pagera. Czy nie zmierzyłeś się z tym problemem? –

20

może to osiągnąć przez nadrzędne onPageSelected sposób OnPageChangeListener. Rozważ, że masz trzy strony w tej kolejności A<->B<->C. Celem jest osiągnięcie C, jeśli przewiniemy w prawo od A i podobnie, aby osiągnąć A, jeśli przewiniemy w lewo od C.

Aby to zrobić, należy zdefiniować swój mieć 5 stron (3 + 2) i zorganizować stron następująco:

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

Teraz w metodzie onPageSelected sprawdzić i jeśli pozycja ma wartość 0, zmień ją na 3 (getCount()-2), a jeśli pozycja to 4 (getCount()-1), zmień ją na 1. Upewnij się, aby użyć metody:

setCurrentItem(item, smoothScroll) 

Oto kompletny kod CircularPagerAdaptor Klasa:

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

A oto w jaki sposób można go używać:

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

Hej, proszę wyjaśnij to dokładniej, spróbował, ale się nie udało. – krisDrOid

+2

która część była myląca? Krótko mówiąc, dodaję dwie fałszywe strony w obu kierunkach, a po ich wybraniu przeniosłem selekcję do rzeczywistego miejsca. – Z0lenDer

+0

Wielkie dzięki !!!!!!! – Chaitu

4

Rozszerzając Z0lenDer Odpowiedź, gdy używasz zwykłego ViewPager, gdzie nie potrzebujesz zwolnić pamięci dla każdego powiązanego widoku, jest bardziej efektywny przechowuj utworzone widoki, a nie identyfikatory układu. Jest to konieczne, jeśli chcesz pozbyć się opóźnienia i migotać, gdy przedmiot jest przełączany.

Występuje również problem z animacją podczas korzystania z onPageSelected, ponieważ nie pozwala ona zakończyć slajdu przed wykonaniem przełącznika.Jedynym sposobem uniknięcia tego jest wykonanie przełącznika tylko po zmianie stanu przewijania na SCROLL_STATE_IDLE i ustawieniu bieżącego elementu na 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

Spróbuj tego

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

To powinno być umieszczone wewnątrz

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

Używałem go w ten sposób, układy fragmentu w adapterze 0 > 1> 2> 3> 4> 5, 5 są obojętne

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

cóż to pomogło

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

    } 
} 

Został @ tobi_b na answer

Powiązane problemy