【问题标题】:Implementing Circular Scrolling In PagerAdapter在 PagerAdapter 中实现循环滚动
【发布时间】:2011-11-23 08:23:19
【问题描述】:

我正在使用 PagerAdapter 进行水平滑动以在我的应用中显示报纸页面。

目前我想在这个应用程序中实现循环滚动。现在我所做的是whenever I am getting on last page I try to set the currentItem to first pagei.e 该功能适用​​于最后一页到第一页,但问题是我如何才能从第一页转到最后一页页。 在这里,我粘贴与 pagerAdapter 和 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);

    }

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

【问题讨论】:

  • 我在文档中看到了一些循环列表适配器 ....
  • 你在说哪个文档是 Android 文档还是其他文档。

标签: android adapter android-viewpager


【解决方案1】:

我可以通过覆盖OnPageChangeListeneronPageSelected 方法来实现这一点。假设您按此顺序有三页 A&lt;-&gt;B&lt;-&gt;C。如果我们从A 向右滚动,目标是到达C,如果我们从C 向左滚动,同样到达A

为此,请将您的页面定义为 5 个页面 (3+2),并按如下方式组织页面:

C&lt;-&gt;A&lt;-&gt;B&lt;-&gt;C&lt;-&gt;A

现在在onPageSelected 方法中,检查如果位置是0,则将其更改为3getCount()-2),如果位置是4getCount()-1),则将其更改为1 .确保使用方法:

setCurrentItem(item, smoothScroll)

这是 CircularPagerAdaptor 类的完整代码:

package zolender.adapters;

import android.content.Context;
import android.os.Parcelable;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.view.LayoutInflater;
import android.view.View;

public class CircularPagerAdapter extends PagerAdapter{

    private int[] pageIDsArray;
    private int count;

    public CircularPagerAdapter(final ViewPager pager, int... pageIDs) {
        super();
        int actualNoOfIDs = pageIDs.length;
        count = actualNoOfIDs + 2;
        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];

        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 onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
                // TODO Auto-generated method stub
            }

            @Override
            public void onPageScrollStateChanged(int state) {
                // TODO Auto-generated method stub
            }
        });
    }

    public int getCount() {
        return count;
    }

    public Object instantiateItem(View container, int position) {
        LayoutInflater inflater = (LayoutInflater) container.getContext()
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        int pageId = pageIDsArray[position];
        View view = inflater.inflate(pageId, null);
        ((ViewPager) container).addView(view, 0);
        return view;
    }

    @Override
    public void destroyItem(View container, int position, Object object) {
        ((ViewPager) container).removeView((View) object);
    }

    @Override
    public void finishUpdate(View container) {
        // TODO Auto-generated method stub
    }

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

    @Override
    public void restoreState(Parcelable state, ClassLoader loader) {
        // TODO Auto-generated method stub
    }

    @Override
    public Parcelable saveState() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public void startUpdate(View container) {
        // TODO Auto-generated method stub
    }
}

你可以这样使用它:

myPager = (ViewPager) findViewById(R.id.myfivepanelpager);
PagerAdapter adapter = new CircularPagerAdapter(myPager, new int[]{R.layout.farleft, R.layout.left, R.layout.middle, R.layout.right, R.layout.farright});
myPager.setAdapter(adapter);
myPager.setCurrentItem(3);

【讨论】:

  • 嘿,你能不能用更准确的方式解释一下,它试过了,但没有成功。
  • 哪一部分令人困惑?简而言之,我在两个方向上添加了两个虚拟页面,当它们被选中时,我将选择移动到它的实际位置。
  • 使用 onPageScrollStateChanged 代替 onPageSelected 以获得更流畅的滚动动画。 @Override public void onPageScrollStateChanged(int state) { if (state == ViewPager.SCROLL_STATE_IDLE) { int pageCount = getCount(); int currentItem = mViewPager.getCurrentItem(); if (currentItem == 0) { mViewPager.setCurrentItem(pageCount - 2, false); } else if (currentItem == pageCount - 1) { mViewPager.setCurrentItem(1, false); } } }
  • @kaupov 如果你能把它作为答案可能会更好,所以编码风格看起来更好:)
  • @Z0lenDer 使用上面的代码可以完美地滑动到三个屏幕,但是 A 和 C 的 View("onActivityCreated") 没有更新你能帮我吗:-(
【解决方案2】:

我还需要一个圆形 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;
    }

}

【讨论】:

  • :- 谢谢你的回答。我会试试这个东西并尽快回复你。
  • @efeyc 谢谢!! pager.setOnTouchListener(..) 解决了我所有的问题!
  • @efeyc MotionEvent e1 在 onFling() 中始终为空。可能是因为视图寻呼机自己的滑动实现。你没遇到过这个问题吗?
【解决方案3】:

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

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

    });

【讨论】:

    【解决方案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】:

      我是这样用的, 适配器 0>1>2>3>4>5 中的片段布局, 0 & 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);
                  }
              }
          });
      

      【讨论】:

        【解决方案6】:

        这有帮助

         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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2018-11-26
          • 1970-01-01
          • 1970-01-01
          • 2011-06-10
          • 1970-01-01
          • 2018-12-09
          • 1970-01-01
          相关资源
          最近更新 更多