Как сделать круговую прокрутку на ViewPager?

Я хочу, чтобы мой ViewPager выполнял круговую прокрутку. Я хочу, чтобы первая страница могла прокручиваться до страницы 2 И последней страницы. И мне бы хотелось, чтобы моя последняя страница прокручивалась до [последней страницы -1] и первой страницы. Я сделал попытку, хотя я не уверен, когда нужно вызвать метод, который я создал. В ViewPager, похоже, не существует метода, который обрабатывает такие вещи, поэтому я создал ниже.

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

            }
        });
    }

Весь мой код довольно длинный, но если это помогает, я могу его опубликовать.

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

Спасибо заранее. Я думал о попытке использовать жест движения, однако, я действительно не понимаю, почему мой метод не будет работать так долго, что я могу назвать его в правильном месте. Моя первоначальная мысль заключалась в том, чтобы вызвать его в "Object instantiateItem (контейнер ViewGroup, конечная позиция int)" каждый раз, когда позиция изменяется, и если условия были правильными. Но я не уверен, что это лучше всего.

Ответ 1

Хорошо, у меня есть ответ. Это было на самом деле легче, чем я ожидал, но это требует некоторого обмана. Во-первых, позвольте мне начать с создания. Допустим, например, у вас есть три страницы (A-B-C), которые вы прокручиваете в своем ViewPager. И вы хотите настроить его так, чтобы, если вы продолжаете прокручивать C (стр. 3), он переходит к A (стр. 1), и если вы прокручиваете назад на A (стр. 1), он переходит на C (стр. 3)).

Я не говорю, что мое решение - лучшее, но оно работает, и я не вижу никаких проблем. Во-первых, вам нужно создать две "поддельные" страницы. Поддельные страницы представляют собой первую и последнюю страницы вашего ViewPager. Следующее, что вам понадобится, это настроить onPageChangeListener() и использовать метод onPageSelected(). Причина, по которой вам нужны поддельные страницы, - это то, что onPageSelected() регистрируется только после перемещения (swiped). Другими словами, без этого метода конечный пользователь должен будет прокручиваться до страницы 2 и вернуться на страницу 1, чтобы получить попадание на страницу 1, что также означает, что страница 1 будет пропущена в зависимости от вашей логики кода.

Настройка - это действительно весь ответ. Когда у вас есть свои поддельные страницы, это просто вопрос использования setCurrentItem() внутри необходимого метода.

Вот как выглядит мой код. Обязательно поместите это в свой общедоступный Object instantiateItem (окончательный контейнер ViewGroup, конечная позиция int) непосредственно перед возвратом вашего представления внутри вашего контейнера.

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

            }

Что это, он делает трюк! Единственное, что нужно сделать, это запустить свой ViewPager в позиции 1 (это вторая страница: fake page = pg 1, моя реальная стартовая страница = pg 2). Теперь, каждый раз, когда я просматриваю поддельную страницу, я перенаправляю ее назад на последнюю реальную страницу. И каждый раз, когда я прокручиваю страницу до последней поддельной страницы, я перенаправляю ее вперед на настоящую стартовую страницу (стр. 2).

Кроме того, не пытайтесь помещать какой-либо код в onPageScrollStateChanged. Этот метод причудливый, кажется, что значение состояния неуправляемо. Он постоянно перескакивает из одного состояния в другое. Даже без прокрутки. Это всего лишь подсказка, которую я взял.

Ответ 2

Это решение без поддельных страниц и работает как шарм:

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

Вам просто нужно установить его в свой ViewPager как onPageChangeListener и что он:

viewPager.setOnPageChangeListener(new CircularViewPagerHandler(viewPager));

Чтобы избежать синего блеска на "конце" вашего ViewPager, вы должны применить эту строку к своему xml, где размещен ViewPager:

android:overScrollMode="never"

Ответ 3

Я создал круговой viewpager с плавным прокруткой от последнего до первого в салфетке слева и сначала до последнего во время салфетки справа.

для этого добавьте последнюю страницу в начале и первой странице до последней: внутри addOnPageChangeListener: мы должны сделать некоторые вычисления, когда мы находимся в 0 позиции, а затем onPageScrollStateChanged задает текущий элемент как последний элемент и наоборот.

Посмотрите на код

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

//адаптер пейджера

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

}

//фрагмент для отображения в адаптере

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

}

}

Ответ 4

Попробуйте это

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

Это должно быть помещено внутри

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

Ответ 5

Я немного изменил ответ от @portfoliobuilder. Это очень просто. Установка текущего элемента без плавной прокрутки до PageChangeState для "0", поэтому он будет очень плавным.

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

Ответ 6

Это мое решение:

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>

Предполагается, что массив имеет 10 элементов. Затем добавьте два фиктивных элемента, но не добавьте их. Когда вызывается функция "get_count", просто возвращайте размер = 10 + 2 элемента.

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

В viewPager.addOnPageChangeListener:

когда вы переходите к последнему элементу, viewPager должен установить первый элемент следующим образом.

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

когда вы переходите к первому элементу, viewPager должен установить последний элемент следующим образом.

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

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

Ответ 7

Я попробовал решение @portfoliobuilder, это здорово. Но есть крошечная проблема: когда текущий элемент - это голова или хвост, если я просто нажму ViewPager, а не перетащить, элемент изменится на хвост или голову. И я добавил сенсорный прослушиватель ViewPager для решения проблемы.

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

Ниже приведена измененная функция 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);
    }
}

Ответ 8

Ответ @tobi_b не является полностью успешным, так как он не плавно перетекает от последнего к первому (по крайней мере, в моей пробной версии). Но я был действительно вдохновлен его ответом. Мое решение - когда нужно перепрыгнуть с поддельной последней до реальной, дождитесь окончания последнего прокрутки. Вот мой код, это очень просто,

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

}

Однако это решение не является совершенным. У этого есть небольшой недостаток, когда слайд быстро от последнего к первому. Если мы сдвинем два раза за очень короткое время, второй слайд станет недействительным. Эта проблема должна быть решена.

Ответ 9

Исправлено отсутствие анимации при движении справа налево при прокрутке первой страницы до последней и наоборот

Небольшая модификация ответа @tobi_b, решила мою проблему. для этого добавьте копию последней страницы в начале и первой странице до последней. Затем просто удалите оператор NOT из приведенного ниже метода в PagerAdapter. И измените setCurrentItem (lastposition, false) на setCurrentItem (lastposition-1, false) и setCurrentItem (0, false) в 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);
    }
}

И в вашем MainActivity.java не забудьте установить текущий элемент как 1. Надеюсь, это поможет некоторым.

Ответ 10

Это простой пример, важной частью слушателя является обнаружение STATE_IDLE конечной точки цикла. поэтому сначала реализуйте класс OnPageChangeListener, затем в своем классе обработчика добавьте эту часть:

@Override
    public void onPageScrollStateChanged(int state) {

        if (state == ViewPager.SCROLL_STATE_IDLE) {

            if (mPreviousPosition == mCurrentPosition && !mIsEndOfCycle) {

                if (mCurrentPosition == 0) {
                    mViewPager.setCurrentItem(getAdapterItemsCount() - 1);
                } else {
                    mViewPager.setCurrentItem(0);
                }

                mIsEndOfCycle = true;
            } else {
                mIsEndOfCycle = false;
            }

            mPreviousPosition = mCurrentPosition;
        }

    }