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.

  • How to quit android application programmatically
  • How is TabItem used when placed in the layout XML?
  • How to prevent the Android Market from JPEG-compressing the Promotional Graphic PNG?
  • How do I install the same Android App .apk twice on the same device?
  • How to start developing applications for Android?
  • How to display date picker for android with only month and year fields?
  • 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.

  • Can we use Guid as a Primary Key in Sqlite Database
  • Is there any Android XML documentation?
  • How to install Google Play Services in a Genymotion VM (with no drag and drop support)?
  • Kill another application on Android?
  • sendUserActionEvent() mView== null after clicking on button
  • Shared element activity transition on android 5
  • 9 Solutions collect form web for “How to do circular scrolling on ViewPager?”

    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) {
                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, false);
            } else if(mCurrentPosition == lastPosition) {
                mViewPager.setCurrentItem(0, false);
            }
        }
    
        @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"
    

    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.

    Try this

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

    This should be placed inside

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

    This is my solution:

    myViewPager.java

    public class myViewPager extends PagerAdapter {
    
        public myViewPager (Context context) {
            this.context = context;
        }
    
        @Override
        public int getCount() {
            return rank.length+2;
        }
    
        @Override
        public boolean isViewFromObject(View view, Object object) {
            return view == object;
        }
    
        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            // Declare Variables
    
            TextView textViewRank;
    
    
    
            //Log.i(TAG, "get position = "+position);
    
            inflater = (LayoutInflater) context
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            View itemView = inflater.inflate(R.layout.viewpager_item, container,
                false);
    
            textViewRank= (TextView) itemView.findViewById(R.id.textView1);
    
            if (position == getCount() - 1) {
                textViewRank.setText(rank[0]);
            } else if (position == 0) {
                textViewRank.setText(rank[rank.length-1]);
            } else {
                textViewRank.setText(rank[position-1]);
            }
    
    
            ((ViewPager) container).addView(itemView);
    
            return itemView;
        }
        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            container.removeView((View) object);
        }
    }
    

    viewpager_item.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:orientation="horizontal" android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <TextView
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:id="@+id/textView1"/>
    </LinearLayout>
    

    MainActivity.java

    public class MainActivity extends AppCompatActivity {
        private static final String TAG = MainActivity.class.getName();
        public static String[] rank;
        myViewPager adapter;
        private ViewPager viewPager;
        private static int currentPage;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            rank = new String[] { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" };
            viewPager = (ViewPager) findViewById(R.id.view_pager);
            adapter = new myViewPager(this);
    
            viewPager.setAdapter(adapter);
    
            viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
                @Override
                public void onPageSelected(int position) {
                    Log.i(TAG, "onPageSelected = "+position);
                    currentPage = position;
                }
                @Override
                public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
                    // not needed
                }
                @Override
                public void onPageScrollStateChanged(int state) {
                    if (state == ViewPager.SCROLL_STATE_IDLE) {
                        int pageCount = rank.length+2;
    
                        if (currentPage == pageCount-1){
                            viewPager.setCurrentItem(1,false);
                        } else if (currentPage == 0){
                            viewPager.setCurrentItem(pageCount-2,false);
                        }
                    }
                }
            });
        }
    
    
    }
    

    activity_main.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical" android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <android.support.v4.view.ViewPager
            android:id="@+id/view_pager"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_weight="1" />
    
    </LinearLayout>
    

    Assumed that the array has 10 elements. Then “add” 2 dummy elements, but not really add. When “get_count” function is called, just return size=10+2 elements.

    dummy e[0] e[1] e[2] e[3] e[4] e[5] e[6] e[7] e[8] e[9] dummy

    In viewPager.addOnPageChangeListener:

    when you slide to the last element, viewPager should set the first element as next.

    if (currentPage == pageCount-1){
        viewPager.setCurrentItem(1,false);
    }
    

    when you slide to the first element, viewPager should set the last element as next.

    else if (currentPage == 0){
        viewPager.setCurrentItem(pageCount-2,false);
    }
    

    In instantiateItem :

     if (position == getCount() - 1) {
        textViewRank.setText(rank[0]);
     } else if (position == 0) {
        textViewRank.setText(rank[rank.length-1]);    
     } else {
        textViewRank.setText(rank[position-1]);
     }
    

    I tried @portfoliobuilder’s solution, it’s great. But there’s a tiny problem: when the current item is the head or the tail, if I just click the ViewPager, not drag, the item will change to the tail or the head. And I added a touch listener to the ViewPager to solve the problem.

    skinPager.setOnTouchListener(new OnTouchListener() {
    
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                //Record the x when press down and touch up, 
                //to judge whether to scroll between head and tail
                int x = (int) event.getX();
                int y = (int) event.getY();
                if(event.getAction() == MotionEvent.ACTION_DOWN)
                    skinPagerPressX = x;
                else if(event.getAction() == MotionEvent.ACTION_UP)
                    skinPagerUpX = x;
                return false;
            }
        });
    

    The following is the modified function of portfoliobuilder:

    private void handleSetNextItem() {
        final int lastPosition = skinPager.getAdapter().getCount() - 1;
        //Only scroll when dragged
        if(mCurrentPosition == 0 && skinPagerUpX > skinPagerPressX) {
            skinPager.setCurrentItem(lastPosition, false);
        } else if(mCurrentPosition == lastPosition && skinPagerUpX < skinPagerPressX) {
            skinPager.setCurrentItem(0, false);
        }
    }
    

    The answer of @tobi_b is not totally successful, since it doesn’t slide smoothly from the last to the first(At least in my trial). But I was really inspired by his answer.
    My solution is when it’s time to jump from the fake last to the real first, wait until last scroll finished. Here is my code, it’s very simple,

    private final class MyPageChangeListener implements OnPageChangeListener {
    
        private int currentPosition;
    
        @Override
        public void onPageScrollStateChanged(int state) {
            if (state == ViewPager.SCROLL_STATE_IDLE) {
                if (currentPosition == viewPager.getAdapter().getCount() - 1) {
                    viewPager.setCurrentItem(1, false);
                }
                else if (currentPosition == 0) {
                    viewPager.setCurrentItem(viewPager.getAdapter().getCount() - 2, false);
                }
            }
        }
    
        @Override
        public void onPageScrolled(int scrolledPosition, float percent, int pixels) {
            //empty
        }
    
        @Override
        public void onPageSelected(int position) {
            currentPosition = position;
        }
    
    }
    

    However, this solution is not perfect. It has a little flaw when slide fast from the last to the first. If we slide twice in a very short time, the second slide will invalidate. This problem need to be solved.

    I have created the circular viewpager with smooth scroll from last to first in swipe left and first to last during swipe right.

    for this add the last page in the starting and the first page to the last:
    inside addOnPageChangeListener : we have to do some calculation , when we are 0 position then on onPageScrollStateChanged set the current item as the last item and vise-versa.

    Have a look to the code

    public class ViewPagerCircular_new extends AppCompatActivity {
    ViewPager viewPager;
    ArrayList<String> str = new ArrayList<String>();
    boolean chageImage = false;
    int setPos;
    
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.view_pager_normal);
        viewPager = (ViewPager) findViewById(R.id.vf_home_top_pager);
        str.add("6");         // added the last page to the frist
        str.add("1");        // First item to display in view pager
        str.add("2");
        str.add("3");
        str.add("4");
        str.add("5");
        str.add("6");     // last item to display in view pager
        str.add("1");      // added the first page to the last
        ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
        viewPager.setAdapter(adapter);
        viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener()
        {
    
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels)
            {
                if (position == str.size() - 1)
                {
                    chageImage = true;
                    setPos = 1;
                } else if (position == 0)
                {
                    chageImage = true;
                    setPos = str.size() - 2;
                } else
                {
                    chageImage = false;
                }
            }
    
            @Override
            public void onPageSelected(int position)
            {
            }
    
            @Override
            public void onPageScrollStateChanged(int state)
            {
                if (state == ViewPager.SCROLL_STATE_IDLE && chageImage)
                {
                    viewPager.setCurrentItem(setPos, false);
                }
            }
        });
    // display the 1st item as current item 
        viewPager.setCurrentItem(1);
    }
    

    // pager adapter

    public class ViewPagerAdapter extends FragmentStatePagerAdapter
    {
    
        public ViewPagerAdapter(FragmentManager fm)
        {
            super(fm);
        }
    
        @Override
        public Fragment getItem(int position)
        {
            PagerFragment fragment = new PagerFragment();
            Bundle bundle = new Bundle();
            bundle.putString("pos", str.get(position));
            fragment.setArguments(bundle);
            return fragment;
        }
    
        @Override
        public int getCount()
        {
            return str.size();
        }
    
    }
    

    // fragment to display in adapter

    public class PagerFragment extends Fragment
    {
    
        Bundle bundle;
        String pos;
    
        public PagerFragment()
        {
        }
    
        @Override
        public void onCreate(Bundle savedInstanceState)
        {
            super.onCreate(savedInstanceState);
            bundle = getArguments();
            pos = bundle.getString("pos");
        }
    
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
        {
            TextView textView = new TextView(ViewPagerCircular_new.this);
            textView.setGravity(Gravity.CENTER);
            textView.setTextSize(25);
            textView.setText(pos);
            return textView;
        }
    
    }
    

    }

    I slightly modified the answer from @portfoliobuilder. It’s very simple.
    Setting the current item with no smooth scroll until PageChangeState to be “0”, so it would be very smooth.

    ((ViewPager)container).setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
    
        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
    
        }
    
        @Override
        public void onPageSelected(int position) {
            currentPage = position;
        }
    
        @Override
        public void onPageScrollStateChanged(int state) {
    
            // state equals to 0 means the scroll action is stop
            if(state == 0) {
    
                if(currentPage == 0)
                    ((ViewPager)container).setCurrentItem(imageResourceList.size()-2,false);
    
                if(currentPage == imageResourceList.size()-1)
                    ((ViewPager)container).setCurrentItem(1,false);
            }
        }
    });
    

    Solved the missing of animation while going from right to left on swiping first page to last and vice-versa

    A slight modification in @tobi_b answer,solved my issue.
    for this add copy of the last page in the starting and the first page to the last.Then just remove the NOT operator from the below method in PagerAdapter.And change setCurrentItem(lastposition,false) to setCurrentItem(lastposition-1,false) and setCurrentItem(0,false) to setCurrentItem(1,false).

    private void setNextItemIfNeeded() {
        if (isScrollStateSettling()) {
            handleSetNextItem();
        }
    }
    
    private boolean isScrollStateSettling() {
        return mScrollState == ViewPager.SCROLL_STATE_SETTLING;
    }
    private void handleSetNextItem() {
        final int lastPosition = pager.getAdapter().getCount() - 1;
        if(mCurrentPosition == 0) {
            pager.setCurrentItem(lastPosition-1, false);
        } else if(mCurrentPosition == lastPosition) {
           pager.setCurrentItem(1, false);
        }
    }
    

    And in your MainActivity.java dont forget to set the current item as 1.
    Hoping this will help some.

    Android Babe is a Google Android Fan, All about Android Phones, Android Wear, Android Dev and Android Games Apps and so on.