如何在ViewPager上进行循环滚动?

por*_*der 29 android scroll android-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()");

            }
        });
    }
Run Code Online (Sandbox Code Playgroud)

我的整个代码有点冗长,但如果有帮助我可以发布它.

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
Run Code Online (Sandbox Code Playgroud)

提前致谢.我正在考虑尝试使用动作手势,但是,我真的不明白为什么我的方法不能工作这么久以至于我可以在正确的位置调用它.我最初的想法是每次位置改变时调用它在"Object instantiateItem(ViewGroup容器,最终的int位置)",如果条件是正确的.但我不确定这是不是最好的.

tob*_*i_b 41

这是一个没有虚假页面的解决方案,就像一个魅力:

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) {
    }
}
Run Code Online (Sandbox Code Playgroud)

您只需将其设置为您的ViewPager作为onPageChangeListener,就是这样:

viewPager.setOnPageChangeListener(new CircularViewPagerHandler(viewPager));
Run Code Online (Sandbox Code Playgroud)

为了避免在ViewPager的"结尾"出现这种蓝色光芒,您应该将此行应用于放置ViewPager的xml:

android:overScrollMode="never"
Run Code Online (Sandbox Code Playgroud)

  • 你不能保持滑动动画,如果从laspage到第1年代从右向左移动,第一页出现没有任何动画和副作用,而且如果你启用平滑滚动,在他的代码中它会来回跳转到第1页和最后一页in infiniteloop - > mViewPager.setCurrentItem(0,true); (17认同)
  • 嗨!我尝试了你的答案,如果你要在*mViewPager.setCurrentItem(0,true)中启用***平滑滚动**,那么它会继续滚动来回. (4认同)
  • 嗨,我通过这个检查做了下一步来修复平滑滚动:if(state == ViewPager.SCROLL_STATE_IDLE && mScrollState == ViewPager.SCROLL_STATE_DRAGGING) (4认同)
  • 我已经改进了上面的解决方案并在github上创建了一个小库.随意检查出来:) https://github.com/TobiasBuchholz/CircularViewPager (3认同)
  • 谢谢,但滚动不顺畅,上面的提示没有帮助. (3认同)
  • @tobi_b不推荐使用ViewPager类方法setOnPageChangeListener(listener),因此您必须使用addOnPageChangeListener(listener).有关详细信息,请查看此http://stackoverflow.com/questions/30867852/viewpager-setonpagechangelistener-deprecated (2认同)

por*_*der 16

好的,我有一个答案.它实际上比我想象的要容易,但确实需要一些技巧.首先,让我从设置开始.可以说,例如,您在ViewPager中滚动浏览了三个页面(ABC).并且你想要设置它,这样如果你继续滚动C(第3页),它会转到A(第1页),如果你在A(第1页)上向后滚动它会转到C(第3页) ).

我不是说我的解决方案是最好的,但它有效,我没有看到任何问题.首先,您必须创建两个"假"页面.虚假页面代表ViewPager的第一页和最后一页.接下来你需要设置一个onPageChangeListener(),并使用onPageSelected()方法.您需要假页面的原因是因为onPageSelected()仅在您移动(滑动)后注册.换句话说,如果没有这种方法,最终用户将不得不滚动到第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!
                }

            }
Run Code Online (Sandbox Code Playgroud)

就是这样,它就是诀窍!唯一要做的就是在第1位开始你的ViewPager(这是第二页:假页=第1页,我的真实起始页=第2页).现在,每次滚动到假页面时,我都会将其重定向到最后一个真实页面.每次我向前滚动到最后一个假页面时,我都会将其重定向到真正的起始页面(第2页).

另外,不要尝试在onPageScrollStateChanged中放入任何代码.这种方法很奇怪,似乎状态值是无法控制的.它不断从一个州跳到另一个州.即使没有滚动.这只是我提到的一个提示.

  • 完美,但如何使滚动顺畅? (4认同)