Implementación de desplazamiento circular en PagerAdapter

Estoy utilizando PagerAdapter para el desplazamiento horizontal para mostrar las páginas de los periódicos en mi aplicación.

Actualmente quiero implementar el desplazamiento circular en esta app.Right ahora lo que he hecho es whenever I am getting on last page I try to set the currentItem to first page es decir, que la funcionalidad de trabajo para la última página a la primera página, pero el problema es Que cómo puedo ir a la última página de la primera página. Aquí estoy pegando mi código relacionado con 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); } } } }); 

También el PagerAdapter es decir AwesomweAdapter en mi caso, también es como 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); } 

Por favor, déme cualquier sugerencia / cambios en mi código (si corresponde) para ello. Gracias por adelantado.

Podría lograr esto mediante la onPageSelected método de OnPageChangeListener . Considere que tiene tres páginas en este orden A<->B<->C El objetivo es llegar a C si nos desplácese desde A y de manera similar para llegar a A si nos desplazamos hacia la izquierda desde C

Para ello, defina su para tener 5 páginas (3 + 2), y organizar las páginas de la siguiente manera:

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

Ahora en el método onPageSelected , marque y si la posición es 0 , cambie a 3 ( getCount()-2 ) y si la posición es 4 ( getCount()-1 ), cambie a 1 . Asegúrese de utilizar el método:

 setCurrentItem(item, smoothScroll) 

Aquí está el código completo para CircularPagerAdaptor Clase:

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

Y aquí está cómo usted puede utilizarlo:

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

También necesitaba un ViewPager circular. Esto es lo que he hecho. Asumo que usted consigue el valor de pageCount de en alguna 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) { } }); 

Y aquí está el GestureDetector. Copiado de aquí

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

Ampliando la respuesta de Z0lenDer , cuando se utiliza un ViewPager regular donde no es necesario liberar la memoria para cada vista asociada, es más eficiente almacenar las vistas creadas en lugar de las ID de diseño. Esto es necesario si desea deshacerse de cualquier retraso y parpadeo cuando se cambia el elemento.

También hay un problema con la animación al usar onPageSelected , ya que no deja que la diapositiva termine antes de hacer el cambio. La única manera que encontré para evitar esto es sólo realizar el cambio una vez que el estado de desplazamiento ha cambiado a SCROLL_STATE_IDLE y acaba de establecer el elemento actual en 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); } } } }); 

Prueba esto

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

Esto debe colocarse dentro

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

Lo usé de esta manera, los diseños de fragmentos en el adaptador 0> 1> 2> 3> 4> 5, 0 & 5 son dummy

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

Bueno, esto ayudó

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

Fue la respuesta de @ tobi_b

  • FragmentPagerAdapter - cómo detectar un golpe o un clic de pestaña cuando el usuario va a una nueva pestaña?
  • Los datos anteriores se muestran en ViewPager Android
  • Android ViewPager Excepción después de pulsar el botón Atrás
  • ViewPager + FragmentStatePagerAdapter + cambio de orientación
  • FragmentTabHost - No se conoce ninguna pestaña null
  • OnPageSelected no funciona para la primera página
  • 2 ViewPager no se desplaza en Android 2.3
  • Objetos de comunicación entre fragmentos múltiples en ViewPager
  • ¿Cómo puedo establecer una etiqueta para fragmentos de viewpager?
  • Deshabilitar la paginación de ViewPager cuando el reciclador de niños se desplaza al último elemento
  • ¿Por qué ViewPager genera errores en el modo de diseño de Android Studio?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.