在PagerAdapter中实现循环滚动

时间:2011-11-23 08:23:19

标签: android adapter android-viewpager

我正在使用PagerAdapter进行横向滑动,以便在我的应用中显示报纸页面。

目前我想在这个应用程序中实现循环滚动。现在我所做的是whenever I am getting on last page I try to set the currentItem to first page,即该功能适用​​于最后一页到第一页,但问题是如何进入最后一页从第一页开始。 在这里,我粘贴了与pagerAdapter& amp; onPageChangeListener: -

    awesomeAdapter = new AwesomePagerAdapter(awesomePager);
    awesomePager.setAdapter(awesomeAdapter);
    awesomePager.setPageMargin(10);
    awesomePager.setOnPageChangeListener(new OnPageChangeListener() {

        int lastPosition;
        float posOffset = 0;
        @Override
        public void onPageSelected(int position) {
               viewerPage = position;
               CommonLogic.logMessage("Viewer Page:- "+ viewerPage, TAG, Log.VERBOSE);
               posOffset = 0;
        }

        @Override
        public void onPageScrolled(int position,float positionOffset,int positionOffsetPixels) {
            if (positionOffset == 0 && positionOffsetPixels == 0 && position != 0) {
                    lastPosition = position;
            }

            posOffset -= positionOffset;

            CommonLogic.logMessage(" Position:-  "
                                     + position + " Position Offset:- "                                     + positionOffset
                                        + " Position Offset Variable:-  "
                                        + posOffset
                                        + "  Position Offset Pixels:- "
                                        + positionOffsetPixels
                                        + " Last Position " + lastPosition,
                                        TAG, Log.VERBOSE);

                                CommonLogic.logMessage(" Last Position "
                                        + lastPosition, TAG, Log.VERBOSE);

        }

        @Override
        public void onPageScrollStateChanged(int state) {
                 // To Detect the Last Page & This Sets it to first page.This working fine. 
         if (state == ViewPager.SCROLL_STATE_DRAGGING && viewerPage == (uris.size() - 1)) {
            CommonLogic.logMessage("Scroll State Changed ", TAG,Log.VERBOSE);
            postDelayed(new Runnable() {
               @Override
               public void run() {
                awesomePager.setCurrentItem(0, true);
               }
            }, 200);
        }
// I have also used this to detect whether the user is on first & try to move on last page,but it is not working well.
else if (state == ViewPager.SCROLL_STATE_DRAGGING && (lastPosition == 0 || lastPosition == (uris.size() - 1)) && viewerPage == 0 && posOffset <= 0) {
                                    CommonLogic.logMessage( "Scroll State Changed ", TAG,Log.VERBOSE);
    postDelayed(new Runnable() {
        @Override
        public void run() {
         awesomePager.setCurrentItem((uris.size() - 1), true);
                }
        }, 200);
        } 
}
}
    });

在我的情况下,PagerAdapter即AwesomweAdapter也是如下: -

private class AwesomePagerAdapter extends PagerAdapter {

    ViewPager pdfContainer;
    DocumentNewView documentNewView;
    CustomViewPager customViewPager;

    public AwesomePagerAdapter(CustomViewPager awesomePager) {
        this.customViewPager = awesomePager;
    }

    @Override
    public int getItemPosition(Object object) {
        return POSITION_NONE;
    }

    @Override
    public int getCount() {
        return uris.size();
    }

    public DocumentNewView addViewAt(int position, DocumentNewView mainView) {
        CommonLogic.logMessage("Position of View:- " + position, TAG,
                Log.VERBOSE);
        pdfContainer.addView(mainView);
        return mainView;
    }

    /**
     * Create the page for the given position. The adapter is responsible
     * for adding the view to the container given here, although it only
     * must ensure this is done by the time it returns from
     * {@link #finishUpdate()}.
     * 
     * @param container
     *            The containing View in which the page will be shown.
     * @param position
     *            The page position to be instantiated.
     * @return Returns an Object representing the new page. This does not
     *         need to be a View, but can be some other container of the
     *         page.
     */
    @Override
    public Object instantiateItem(View collection, int position) {
        CommonLogic
                .logMessage("Instantiate Item Called ", TAG, Log.VERBOSE);

        documentNewView = new DocumentNewView(cxt, display, customViewPager);
        documentNewView.setPdfContext(new PdfContext());
        CodecDocument codecDocument = documentNewView.open(uris
                .get(position));
        documentNewView.renderDocument(codecDocument);
        documentNewView.setMaxZoom(4f);
        documentNewView.setVerticalScrollBarEnabled(true);
        codecDocument = null;
        this.pdfContainer = (ViewPager) collection;
        return addViewAt(position, documentNewView);
     }

    /**
     * Remove a page for the given position. The adapter is responsible for
     * removing the view from its container, although it only must ensure
     * this is done by the time it returns from {@link #finishUpdate()}.
     * 
     * @param container
     *            The containing View from which the page will be removed.
     * @param position
     *            The page position to be removed.
     * @param object
     *            The same object that was returned by
     *            {@link #instantiateItem(View, int)}.
     */
    @Override
    public void destroyItem(View collection, int position, Object view) {
        pdfContainer.removeView((DocumentNewView) view);

    }

    /**
     * Called when the a change in the shown pages has been completed. At
     * this point you must ensure that all of the pages have actually been
     * added or removed from the container as appropriate.
     * 
     * @param container
     *            The containing View which is displaying this adapter's
     *            page views.
     */
    @Override
    public void finishUpdate(View arg0) {
        CommonLogic.logMessage("Finish Update Called ", TAG, Log.VERBOSE);
    }

    @Override
    public void restoreState(Parcelable arg0, ClassLoader arg1) {
    }

    @Override
    public Parcelable saveState() {
        return null;
    }

    @Override
    public void startUpdate(View arg0) {
        CommonLogic.logMessage("State Update Called ", TAG, Log.VERBOSE);
    }

    @Override
    public boolean isViewFromObject(View view, Object object) {
        return view == ((DocumentNewView) object);

    }

请在我的代码(如果适用)中为我提供任何建议/更改。 提前致谢。

6 个答案:

答案 0 :(得分:21)

我可以通过覆盖onPageSelected的{​​{1}}方法来实现这一点。考虑按此顺序排列有三个页面OnPageChangeListener。如果我们从A<->B<->C向右滚动,目标就是C,如果我们从A向左滚动,则与A类似。

要执行此操作,请将您的页面定义为5页(3 + 2),然后按如下方式组织页面:

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

现在在A方法中,检查以及onPageSelected的位置,将其更改为03),如果位置为getCount()-2({ {1}}),将其更改为4。请务必使用以下方法:

getCount()-1

以下是 CircularPagerAdaptor 类的完整代码:

1

以下是您可以使用它的方法:

setCurrentItem(item, smoothScroll)

答案 1 :(得分:8)

我还需要一个循环的ViewPager。这就是我所做的。我假设你从某个地方获得了pageCount值。

...
    pager = (ViewPager) findViewById(R.id.pager);
    //Gesture detection
    final GestureDetector gestureDetector = new GestureDetector(new MyGestureDetector());
    pager.setOnTouchListener(new OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            return gestureDetector.onTouchEvent(event);
        }
    });

    //pagelistener is just for getting selected page
    pager.setOnPageChangeListener(new OnPageChangeListener() {

        @Override
        public void onPageSelected(int position) {
            selectedPage = position;
        }

        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        }

        @Override
        public void onPageScrollStateChanged(int state) {
        }
    });

这是GestureDetector。 复制自here

    class MyGestureDetector extends SimpleOnGestureListener {

    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {

        int SWIPE_MIN_DISTANCE = Utils.ConvertToPixel(mContext, 50);
        int SWIPE_MAX_OFF_PATH = Utils.ConvertToPixel(mContext, 250);
        int SWIPE_THRESHOLD_VELOCITY = Utils.ConvertToPixel(mContext, 200);

        try {

            if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH)
                return false;
            // right to left swipe
            if(e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE 
                    && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY
                    && selectedPage == (pageCount - 1)) {
                pager.setCurrentItem(0);
                return true;
            }  else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE 
                    && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY
                    && selectedPage == 0) {
                pager.setCurrentItem(pageCount - 1);
                return true;
            }
        } catch (Exception e) {
            // nothing
        }
        return false;
    }

}

答案 2 :(得分:4)

扩展Z0lenDer的答案,当使用常规ViewPager而不需要为每个关联视图释放内存时,存储创建的视图而不是布局更有效标识。如果想要在切换项目时摆脱任何延迟和闪烁,这是必要的。

使用onPageSelected时动画也存在问题,因为在进行切换之前不会让幻灯片完成。我发现避免这种情况的唯一方法是仅在滚动状态更改为SCROLL_STATE_IDLE并且仅在onPageSelected中设置当前项目时执行切换。

private int currentPage = 0;

...

    pager.setOnPageChangeListener(new OnPageChangeListener() {

        @Override
        public void onPageSelected(int position) {
            currentPage = position;
        }

        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

        }

        @Override
        public void onPageScrollStateChanged(int state) {
            // TODO Auto-generated method stub
            Log.d(TAG, "onPageScrollStateChanged: " + state);
            if (state == ViewPager.SCROLL_STATE_IDLE) {
                int pageCount = getCount();
                if (currentPage == 0){
                    pager.setCurrentItem(pageCount-2,false);
                } else if (currentPage == pageCount-1){
                    pager.setCurrentItem(1,false);
                }
            }
        }

    });

答案 3 :(得分:0)

试试这个

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

答案 4 :(得分:0)

我用这种方式, 适配器0中的片段布局&gt; 1&gt; 2&gt; 3&gt; 4&gt; 5, 0&amp; 5是假的

    viewPager.setAdapter(adapter);
    viewPager.setCurrentItem(1, false);        //going to page 1;

    final int[] pagePosition = new int[1];

    viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

        }

        @Override
        public void onPageSelected(int position) {
            pagePosition[0] = position;
        }

        @Override
        public void onPageScrollStateChanged(int state) { //state changes from 2 to 0 during a swipe

            if (state == 0 && pagePosition[0] == 0){            
                viewPager.setCurrentItem(4, false);
            } else if (state == 0 && pagePosition[0] == 5){
                viewPager.setCurrentItem(1, false);
            }
        }
    });

答案 5 :(得分:0)

这有帮助

 private class CircularViewPagerHandler implements ViewPager.OnPageChangeListener {
    private ViewPager mViewPager;
    private int mCurrentPosition;
    private int mScrollState;
    private int mPreviousPosition;

    public CircularViewPagerHandler(final ViewPager viewPager) {
        mViewPager = viewPager;
    }

    @Override
    public void onPageSelected(final int position) {
        mCurrentPosition = position;
        mPreviousPosition = position-1;
    }

    @Override
    public void onPageScrollStateChanged(final int state) {
        if (state == ViewPager.SCROLL_STATE_IDLE) {
            setNextItemIfNeeded();
        }
        mScrollState = state;
    }


    private void setNextItemIfNeeded() {
        if (!isScrollStateSettling()) {
            handleSetNextItem();
        }
    }

    private boolean isScrollStateSettling() {
        return mScrollState == ViewPager.SCROLL_STATE_SETTLING; //indicated page is settling to it's final position
    }

    private void handleSetNextItem() {
        final int lastPosition = mViewPager.getAdapter().getCount() - 1;
        if (mCurrentPosition == 0) {
            mViewPager.setCurrentItem(lastPosition,false);
        } else if (mCurrentPosition == lastPosition) {
            mViewPager.setCurrentItem(0, false);
        }
    }

    @Override
    public void onPageScrolled(final int position, final float positionOffset, final int positionOffsetPixels) {

    }
}

这是@ tobi_b的answer