Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to do circular scrolling on ViewPager?

I would like to set my ViewPager to do circular scrolling. I want the first page to be able to scroll to page 2 AND the last page. And I would like my last page to scroll to [last page -1] AND the first page. I have made an attempt, although I am not sure when to call the method I have created. There does not seem to be a method in ViewPager that handles this sort of thing, so I created the below.

    public ViewPagerAdapter(final ViewPager pager, int... pageIDs) {         super();         int actualNoOfIDs = pageIDs.length;         count = actualNoOfIDs + 2;         Log.d(TAG, "actualNoOfIDs: " + actualNoOfIDs +                 "count: " + count);          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];          Log.d(TAG, "actualNoOfIDs#2: " + actualNoOfIDs +                 "count#2: " + count);         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 onPageScrollStateChanged(int state) {                 // TODO Auto-generated method stub                 Log.d(TAG, "onPageScrollStateChanged()"); //              if (state == ViewPager.SCROLL_STATE_IDLE) {  //                  int pageCount = getCount();  //                  int currentItem = pager.getCurrentItem();  //                  if (currentItem == 0) {  //                      pager.setCurrentItem(pageCount - 2, false);  //                  } else if (currentItem == pageCount - 1) {  //                      pager.setCurrentItem(1, false);  //                  }  //              }               }              @Override             public void onPageScrolled(int position, float positionOffset,                      int positionOffsetPixels) {                 // TODO Auto-generated method stub                 Log.d(TAG, "onPageScrolled()");              }         });     } 

My entire code is sort of lengthy, but if it helps I can post it.

public class ViewPagerAdapter extends PagerAdapter {     public static String TAG = ViewPagerAdapter.class.getSimpleName();      private int count;     private int[] pageIDsArray;      private TextToSpeech btnTTS;     private TtsButton tTSBtn;      String inputTxt;     Context context;     View itemView;      TextView tvNumber; // container for atomic number     TextView tvSymbol; // container for symbol     TextView tvWeight; // container for weight     TextView tvName; // container for name     TextView tvGroup; // container for group     TextView tvPeriod; // container for period     TextView tvBlock; // container for block     TextView tvFamily; // container for family     TextView tvColor; // container for color     TextView tvPhase; // container for phase     TextView tvMelt; // container for melting point     TextView tvBoil; // container for boiling point     TextView tvNeutrons; // container for neutrons     TextView tvProtons; // container for protons     TextView tvElectrons; // container for electrons     TextView tvUrl; // container for electrons      public ViewPagerAdapter(Context context, List<Integer> arrayAtomicNum,              List<String> arrayName, List<String> arraySymbol, List<String> arrayFamily,             List<String> arrayPhase, List<String> arrayColor, List<Integer> arrayGroup,              List<Integer> arrayPeriod, List<String> arrayBlock, List<Integer> arrayProtons,             List<Integer> arrayNeutrons, List<Integer> arrayElectrons, List<Double> arrayWeight,             List<Double> arrayMelt, List<Double> arrayBoil, List<String> arrayUrl) {             this.context = context;         ElementStructure.arrayAtomicNum = arrayAtomicNum;         ElementStructure.arrayName = arrayName;         ElementStructure.arraySymbol = arraySymbol;         ElementStructure.arrayFamily = arrayFamily;         ElementStructure.arrayPhase = arrayPhase;         ElementStructure.arrayColor = arrayColor;         ElementStructure.arrayGroup = arrayGroup;         ElementStructure.arrayPeriod = arrayPeriod;         ElementStructure.arrayBlock = arrayBlock;         ElementStructure.arrayProtons = arrayProtons;         ElementStructure.arrayNeutrons = arrayNeutrons;         ElementStructure.arrayElectrons = arrayElectrons;         ElementStructure.arrayWeight = arrayWeight;         ElementStructure.arrayMelt = arrayMelt;         ElementStructure.arrayBoil = arrayBoil;         ElementStructure.arrayUrl = arrayUrl;     }       public ViewPagerAdapter(final ViewPager pager, int... pageIDs) {         super();         int actualNoOfIDs = pageIDs.length;         count = actualNoOfIDs + 2;         Log.d(TAG, "actualNoOfIDs: " + actualNoOfIDs +                 "count: " + count);          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];          Log.d(TAG, "actualNoOfIDs#2: " + actualNoOfIDs +                 "count#2: " + count);         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 onPageScrollStateChanged(int state) {                 // TODO Auto-generated method stub                 Log.d(TAG, "onPageScrollStateChanged()"); //              if (state == ViewPager.SCROLL_STATE_IDLE) {  //                  int pageCount = getCount();  //                  int currentItem = pager.getCurrentItem();  //                  if (currentItem == 0) {  //                      pager.setCurrentItem(pageCount - 2, false);  //                  } else if (currentItem == pageCount - 1) {  //                      pager.setCurrentItem(1, false);  //                  }  //              }               }              @Override             public void onPageScrolled(int position, float positionOffset,                      int positionOffsetPixels) {                 // TODO Auto-generated method stub                 Log.d(TAG, "onPageScrolled()");              }         });     }      @Override     public int getCount() {         // TODO Auto-generated method stub         return ElementStructure.arrayAtomicNum.size();      }      @Override     public boolean isViewFromObject(View view, Object object) {         // TODO Auto-generated method stub         return view == ((RelativeLayout) object);     }      @Override     public Object instantiateItem(ViewGroup container, final int position) {          LayoutInflater inflater = (LayoutInflater) context              .getSystemService(Context.LAYOUT_INFLATER_SERVICE);          int layoutColorId = ElementStructure.arrayLayoutColor.get(position);          if (layoutColorId == 1) {             itemView = inflater.inflate(R.layout.frame_learn_a, container,                      false);         } else if (layoutColorId == 2) {             itemView = inflater.inflate(R.layout.frame_learn_b, container,                      false);         } else if (layoutColorId == 3) {             itemView = inflater.inflate(R.layout.frame_learn_c, container,                      false);         } else if (layoutColorId == 4) {             itemView = inflater.inflate(R.layout.frame_learn_d, container,                      false);             }          Button btnSpeak = (Button)itemView.findViewById(R.id.btnaudio);          btnSpeak.setOnClickListener(new OnClickListener() {              @Override             public void onClick(View v) {                 // TODO Auto-generated method stub                 inputTxt = ElementStructure.arrayName.get(position);                 tTSBtn = new TtsButton(this, inputTxt);              }          });          // atomic number textView         tvNumber = (TextView)itemView.findViewById(R.id.metanumber);          // symbol textView         tvSymbol = (TextView)itemView.findViewById(R.id.metasymbol);          // weight textView         tvWeight = (TextView)itemView.findViewById(R.id.metaweight);          // name textView         tvName = (TextView)itemView.findViewById(R.id.metaname);          // group textView         tvGroup = (TextView)itemView.findViewById(R.id.metagroup);          // period textView         tvPeriod = (TextView)itemView.findViewById(R.id.metaperiod);          // block textView         tvBlock = (TextView)itemView.findViewById(R.id.metablock);          // family textView         tvFamily = (TextView)itemView.findViewById(R.id.metafamily);          // color textView         tvColor = (TextView)itemView.findViewById(R.id.metacolor);          // phase textView         tvPhase = (TextView)itemView.findViewById(R.id.metaphase);          // melting point textView         tvMelt = (TextView)itemView.findViewById(R.id.metamelt);          // boiling point textView         tvBoil = (TextView)itemView.findViewById(R.id.metaboil);          // neutrons textView         tvNeutrons = (TextView)itemView.findViewById(R.id.metaneutrons);          // protons textView         tvProtons = (TextView)itemView.findViewById(R.id.metaprotons);          // electrons textView         tvElectrons = (TextView)itemView.findViewById(R.id.metaelectrons);          // url textView         tvUrl = (TextView)itemView.findViewById(R.id.metaurl);          // capture position and set to the TextViews         tvNumber.setText(String.valueOf(ElementStructure.arrayAtomicNum.get(position)));         tvSymbol.setText(ElementStructure.arraySymbol.get(position));         tvWeight.setText(String.valueOf(ElementStructure.arrayWeight.get(position)));         tvName.setText(ElementStructure.arrayName.get(position));         tvPeriod.setText(String.valueOf(ElementStructure.arrayPeriod.get(position)));         tvBlock.setText(String.valueOf(ElementStructure.arrayBlock.get(position)));         tvFamily.setText(ElementStructure.arrayFamily.get(position));         tvColor.setText(ElementStructure.arrayColor.get(position));         tvPhase.setText(ElementStructure.arrayPhase.get(position));         tvNeutrons.setText(String.valueOf(ElementStructure.arrayNeutrons.get(position)));         tvProtons.setText(String.valueOf(ElementStructure.arrayProtons.get(position)));         tvElectrons.setText(String.valueOf(ElementStructure.arrayElectrons.get(position)));         tvUrl.setText(ElementStructure.arrayUrl.get(position));          // capture position, adjust for 0 value cases         if (ElementStructure.arrayGroup.get(position) == 0) {             tvGroup.setText("n/a");         } else {             tvGroup.setText(String.valueOf(ElementStructure.arrayGroup.get(position)));         }          if (ElementStructure.arrayMelt.get(position) == 0) {             tvMelt.setText("n/a");         } else {             tvMelt.setText(String.valueOf(ElementStructure.arrayMelt.get(position)));         }          if (ElementStructure.arrayBoil.get(position) == 0) {             tvBoil.setText("n/a");         } else {             tvBoil.setText(String.valueOf(ElementStructure.arrayBoil.get(position)));         }          // add fragments to container (ViewPager)         ((ViewPager) container).addView(itemView);         return itemView;      }      @Override     public void destroyItem(ViewGroup container, int position, Object object) {         Log.d(TAG, "destroyItem()");         // remove fragments from container (ViewPager)         ((ViewPager) container).removeView((RelativeLayout) object);     }       @Override     public void finishUpdate(View container) {         // TODO Auto-generated method stub         Log.d(TAG, "finishUpdate()");     }      @Override     public void restoreState(Parcelable state, ClassLoader loader) {         // TODO Auto-generated method stub         Log.d(TAG, "restoreState()");     }      @Override     public Parcelable saveState() {         // TODO Auto-generated method stub         Log.d(TAG, "saveState()");         return null;     }      @Override     public void startUpdate(View container) {         // TODO Auto-generated method stub         Log.d(TAG, "startUpdate()");     }         public class TtsButton extends Activity implements OnInitListener {          public TtsButton(OnClickListener onClickListener, String inputTxt) {             super();             tTSCheck(inputTxt);         }          private void tTSCheck (String inputTxt) {              int resultCodeCheck = TextToSpeech.Engine.CHECK_VOICE_DATA_PASS;             if (resultCodeCheck == 1) {                 btnTTS = new TextToSpeech(context, this);             } else {                 Intent installTTSFiles = new Intent(); //missing data, install it                 installTTSFiles.setAction(TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA);                 startActivity(installTTSFiles);             }         }          @Override         public void onInit(int status) {             // TODO Auto-generated method stub             if(status == TextToSpeech.SUCCESS)             {                 Log.i(TAG, "TTS INIT: SUCCESS");                 btnTTS.setLanguage(Locale.US);                 btnTTS.speak(inputTxt, TextToSpeech.QUEUE_FLUSH, null);             }             else if(status == TextToSpeech.ERROR)             {                 Log.e(TAG, "TTS INIT: ERROR");             }         }          @Override         public void onPause() {             if (btnTTS != null) {                 btnTTS.stop();                 btnTTS.shutdown();             }             super.onPause();         }      } //end embedded class  } //end ViewPagerAdapter 

Thanks in advance. I was thinking about trying to use motion gesture, however, I really do not understand why my method won't work so long that I can call it in the correct spot. My initial thought was to call it in "Object instantiateItem(ViewGroup container, final int position)" every time the position changes, and if the conditions were correct. But I'm not sure if that is best.

like image 676
portfoliobuilder Avatar asked Jan 26 '14 20:01

portfoliobuilder


People also ask

How to make ViewPager circular in android?

First, you have to create two "fake" pages. The fake pages represent the first and last pages of your ViewPager. The next thing you will need is to set up an onPageChangeListener(), and use the method onPageSelected().

Is ViewPager scrollable?

The ViewPager is populated with fragments taking up space way beyond the screen (vertically). Still, nothing on the screen is scrollable.


2 Answers

This is a solution without fake pages and works like a charm:

public class CircularViewPagerHandler implements ViewPager.OnPageChangeListener {     private ViewPager   mViewPager;     private int         mCurrentPosition;     private int         mScrollState;      public CircularViewPagerHandler(final ViewPager viewPager) {         mViewPager = viewPager;     }      @Override     public void onPageSelected(final int position) {         mCurrentPosition = position;     }      @Override     public void onPageScrollStateChanged(final int state) {         handleScrollState(state);         mScrollState = state;     }      private void handleScrollState(final int state) {         if (state == ViewPager.SCROLL_STATE_IDLE && mScrollState == ViewPager.SCROLL_STATE_DRAGGING) {             setNextItemIfNeeded();         }     }      private void setNextItemIfNeeded() {         if (!isScrollStateSettling()) {             handleSetNextItem();         }     }      private boolean isScrollStateSettling() {         return mScrollState == ViewPager.SCROLL_STATE_SETTLING;     }      private void handleSetNextItem() {         final int lastPosition = mViewPager.getAdapter().getCount() - 1;         if(mCurrentPosition == 0) {             mViewPager.setCurrentItem(lastPosition, true);         } else if(mCurrentPosition == lastPosition) {             mViewPager.setCurrentItem(0, true);         }     }      @Override     public void onPageScrolled(final int position, final float positionOffset, final int positionOffsetPixels) {     } } 

You just have to set it to your ViewPager as onPageChangeListener and that's it:

viewPager.setOnPageChangeListener(new CircularViewPagerHandler(viewPager)); 

To avoid having this blue shine at the "end" of your ViewPager you should apply this line to your xml where the ViewPager is placed:

android:overScrollMode="never" 
like image 147
tobi_b Avatar answered Sep 18 '22 12:09

tobi_b


Ok, I have an answer. It was actually easier than I expected, but it does take some trickery. First, let me begin with the set up. Lets say, for example, you have three pages (A-B-C) that you are scrolling through in your ViewPager. And you want to set it up so that if you continue scrolling on C (pg. 3), it goes to A (pg. 1) and if you scrolled backwards on A (pg. 1) it goes to C (pg. 3).

I am not saying my solution is the best, but it works and I do not see any issues. First, you have to create two "fake" pages. The fake pages represent the first and last pages of your ViewPager. The next thing you will need is to set up an onPageChangeListener(), and use the method onPageSelected(). The reason why you need the fake pages is because onPageSelected() only registers after you have moved (swiped). In other words, without this method the end user would have to scroll to page 2 and back to page 1 to receive a hit on page 1, which also means that page 1 would be skipped depending on your code logic.

The setup is really the entire answer. Once you have your fake pages, it is just a matter of using setCurrentItem() inside the necessary method.

Here is how my code looks. Be sure to place this inside your public Object instantiateItem(final ViewGroup container, final int position) method, just before you return your view inside of your container.

((ViewPager) container).setOnPageChangeListener(new OnPageChangeListener() {             @Override             public void onPageSelected(int position) {                 Log.d(TAG, "onPageSelected() :: " + "position: " + position);                  // skip fake page (first), go to last page                 if (position == 0) {                     ((ViewPager) container).setCurrentItem(118, false);                 }                  // skip fake page (last), go to first page                 if (position == 119) {                     ((ViewPager) container).setCurrentItem(1, false); //notice how this jumps to position 1, and not position 0. Position 0 is the fake page!                 }              } 

That's it, it does the trick! The only other thing to do is start your ViewPager on position 1 (which is the second page: fake page = pg 1, my real starting page = pg 2). Now, every time I scroll to the fake page, I redirect it backwards to the last real page. And every time I scroll forward to the last fake page, I redirect it forwards to the real starting page (pg 2).

Also, do not try to put any code in onPageScrollStateChanged. That method is bizarre, it seems that the state value is uncontrollable. It constantly jumps from one state to another. Even without scrolling. That is just a tip I picked up.

like image 30
portfoliobuilder Avatar answered Sep 18 '22 12:09

portfoliobuilder