【问题标题】:Changing ViewPager to enable infinite page scrolling更改 ViewPager 以启用无限页面滚动
【发布时间】:2011-10-14 10:56:52
【问题描述】:

Jon Willis 发布了如何使用他的代码启用无限滚动。

在那里他说他对android支持库中的ViewPager类做了一些改变。进行了哪些更改,如何使用 ViewPager 更改“重新编译”库?

【问题讨论】:

标签: android android-viewpager infinite-scroll


【解决方案1】:

我非常简单地在适配器中使用了一个小技巧来解决这个问题。这是我的代码:

public class MyPagerAdapter extends FragmentStatePagerAdapter
{
    public static int LOOPS_COUNT = 1000;
    private ArrayList<Product> mProducts;


    public MyPagerAdapter(FragmentManager manager, ArrayList<Product> products)
    {
        super(manager);
        mProducts = products;
    }


    @Override
    public Fragment getItem(int position)
    {
        if (mProducts != null && mProducts.size() > 0)
        {
            position = position % mProducts.size(); // use modulo for infinite cycling
            return MyFragment.newInstance(mProducts.get(position));
        }
        else
        {
            return MyFragment.newInstance(null);
        }
    }


    @Override
    public int getCount()
    {
        if (mProducts != null && mProducts.size() > 0)
        {
            return mProducts.size()*LOOPS_COUNT; // simulate infinite by big number of products
        }
        else
        {
            return 1;
        }
    }
} 

然后,在 ViewPager 中,我们将当前页面设置为中间:

mAdapter = new MyPagerAdapter(getSupportFragmentManager(), mProducts);
mViewPager.setAdapter(mAdapter);
mViewPager.setCurrentItem(mViewPager.getChildCount() * MyPagerAdapter.LOOPS_COUNT / 2, false); // set current item in the adapter to middle

【讨论】:

  • 谢谢!非常适合我的场景!
  • 这是一个不错且简单的解决方案,但随着LOOPS_COUNT 值的增加,性能似乎会下降。我必须将我的设置为 100 左右
  • mProducts 是您的数据列表。 MyFragment 是一个片段,它将显示在寻呼机中。在我的示例中,我有一个产品列表。每个产品都有一个图像和一些其他参数。图片是从 MyFragment 中的 URL 加载的。
  • mViewPager.getChildCount() 返回 0。应替换为 mAdapter.getCount()
  • 使用 ViewPager 的全部意义在于为您管理片段。使用此解决方案,它每次都会创建一个新片段。所以,是的,这个解决方案将对性能产生很大影响。您可能应该从 FragmentStatePagerAdapter 中提取代码并在此处执行取模技巧:if (mFragments.size() &gt; position) { Fragment f = mFragments.get(position); if (f != null) { return f; } }
【解决方案2】:

感谢您的回答 Shereef。

我的解决方法有点不同。

我更改了android支持库的ViewPager类的代码。方法setCurrentItem(int)

用动画改变页面。此方法调用一个内部方法,该方法需要索引和启用平滑滚动的标志。这个标志是boolean smoothScroll。 使用第二个参数 boolean smoothScroll 扩展此方法为我解决了这个问题。 调用这个方法setCurrentItem(int index, boolean smoothScroll) 可以让它无限滚动。

这是一个完整的例子:

请注意只显示中心页面。 此外,我是否将页面单独存储,让我更轻松地处理它们。

private class Page {
  View page;
  List<..> data;
}
// page for predecessor, current, and successor
Page[] pages = new Page[3];




mDayPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {

        @Override
        public void onPageSelected(int position) {
        }

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

        @Override
        public void onPageScrollStateChanged(int state) {

            if (state == ViewPager.SCROLL_STATE_IDLE) {

                if (mFocusedPage == 0) {
                    // move some stuff from the 
                                            // center to the right here
                    moveStuff(pages[1], pages[2]);

                    // move stuff from the left to the center 
                    moveStuff(pages[0], pages[1]);
                    // retrieve new stuff and insert it to the left page
                    insertStuff(pages[0]);
                }
                else if (mFocusedPage == 2) {


                    // move stuff from the center to the left page
                    moveStuff(pages[1], pages[0]); 
                    // move stuff from the right to the center page
                    moveStuff(pages[2], pages[1]); 
                    // retrieve stuff and insert it to the right page
                                            insertStuff(pages[2]);
                }

                // go back to the center allowing to scroll indefinitely
                mDayPager.setCurrentItem(1, false);
            }
        }
    });

但是,如果没有 Jon Willis 代码,我自己就无法解决这个问题。

编辑:这是一个blogpost 关于这个:

【讨论】:

  • 我的 github 项目会很棒
  • 我会尽快写博客。我会在此处以评论的形式通知你们。
  • 那个博客好运吗?
  • 是的,这里:thehayro.blogspot.de/2013/09/… 它实际上在我帖子的底部。
  • 如果我快速滚动,我的应用程序会被阻止。一秒后解锁。我该如何解决这个问题?
【解决方案3】:

通过覆盖现有适配器类中的 4 个适配器方法实现无限视图寻呼机

    @Override
    public int getCount() {
        return Integer.MAX_VALUE;
    }

    @Override
    public CharSequence getPageTitle(int position) {
        String title = mTitleList.get(position % mActualTitleListSize);
        return title;
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        int virtualPosition = position % mActualTitleListSize;
        return super.instantiateItem(container, virtualPosition);
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        int virtualPosition = position % mActualTitleListSize;
        super.destroyItem(container, virtualPosition, object);
    }

【讨论】:

  • 这在向后(左(通过 0)进入底片)时不起作用
  • @MobileMon 从中间开始
  • 设置适配器后,只需添加 yourAwesomePager.setCurrentItem(Integer.MAX_VALUE / 2);从中间开始
  • 不幸的是,将 MAX_VALUE for viewpager 与 setCurrentItem 结合使用时会出现性能问题,这是由于 viewpager 的实现会遍历所有项目。您将获得 ANR / UI 线程块。
  • 创建一个具有无限视图的简单 ViewPager,然后尝试将当前项向后设置两个以上步骤。可能您需要将 pageWidth 设置为很小以允许多个可见条目以触发我正在谈论的“错误”,但错误就在那里。请参阅:stackoverflow.com/questions/18740916/…
【解决方案4】:

实际上,我一直在研究各种方法来进行这种“无限”分页,尽管人类对时间的概念是无限的(尽管我们有时间的开始和结束的概念) ,计算机处理离散。有一个最小和最大时间(可以随着时间的推移进行调整,还记得 Y2K 恐慌的基础吗?)。

无论如何,本次讨论的重点是/应该足以通过实际有限的日期范围来支持相对无限的日期范围。一个很好的例子是 Android 框架的 CalendarView 实现,以及其中的 WeeksAdapter。默认的最小日期是 1900 年,默认的最大日期是 2100 年,这应该很容易涵盖今天周围 10 年内任何人使用日历的 99%。

他们在实施过程中所做的(重点关注周数)是计算最短日期和最长日期之间的周数。这成为寻呼机中的页数。请记住,寻呼机不需要同时维护所有这些页面(setOffscreenPageLimit(int)),它只需要能够根据页码(或索引/位置)创建页面。在这种情况下,索引是该周距最小日期的周数。使用这种方法,您只需要维护最小日期和页数(到最大日期的距离),然后对于任何页面,您都可以轻松计算与该页面关联的星期。 ViewPager 不支持循环(也称为无限分页),并试图强迫它表现得像可以无限滚动一样。

new FragmentStatePagerAdapter(getFragmentManager()) {
    @Override
    public Fragment getItem(int index) {
        final Bundle arguments = new Bundle(getArguments());
        final Calendar temp_calendar = Calendar.getInstance();
        temp_calendar.setTimeInMillis(_minimum_date.getTimeInMillis());
        temp_calendar.setFirstDayOfWeek(_calendar.getStartOfWeek());
        temp_calendar.add(Calendar.WEEK_OF_YEAR, index);
        // Moves to the first day of this week
        temp_calendar.add(Calendar.DAY_OF_YEAR,
                -UiUtils.modulus(temp_calendar.get(Calendar.DAY_OF_WEEK) - temp_calendar.getFirstDayOfWeek(),
                7));
        arguments.putLong(KEY_DATE, temp_calendar.getTimeInMillis());
        return Fragment.instantiate(getActivity(), WeekDaysFragment.class.getName(), arguments);
    }

    @Override
    public int getCount() {
        return _total_number_of_weeks;
    }
};

然后WeekDaysFragment 可以轻松地显示从其参数中传递的日期开始的星期。

另外,Android 上的某些版本的日历应用似乎使用ViewSwitcher(这意味着只有 2 个页面,您看到的页面和隐藏页面)。然后它会根据用户滑动的方式更改过渡动画,并相应地呈现下一个/上一个页面。通过这种方式,您可以获得无限分页,因为它只是在两个页面之间无限切换。不过,这需要为页面使用View,这是我采用第一种方法的方式。

一般来说,如果您想要“无限分页”,可能是因为您的页面以某种方式基于日期或时间。如果是这种情况,请考虑使用相对无限的有限时间子集。例如,这就是 CalendarView 的实现方式。或者您可以使用ViewSwitcher 方法。这两种方法的优点是,ViewSwitcherViewPager 都没有什么特别的不寻常之处,并且不需要任何技巧或重新实现来强制它们无限运行(ViewSwitcher 已经被设计为在视图之间无限切换,但ViewPager 旨在处理有限但不一定是恒定的页面集)。

【讨论】:

    【解决方案5】:

    您需要做的就是查看示例here

    你会发现在第 295 行页面总是设置为 1 以便它可以滚动 并且 getCount() 方法中的页数为 3。

    这是你需要改变的两个主要方面,其余的是你的逻辑,你可以用不同的方式处理它们。

    只需创建一个个人计数器来计算您所在的真实页面,因为在第 295 行始终将当前页面设置为 1 后,位置将不再可用。

    附言此代码不是我的,它在您在问题中链接的问题中被引用

    【讨论】:

      【解决方案6】:

      基于先前示例的无限滑块适配器骨架

      一些关键问题:

      • 记住页面视图中的原始(相对)位置(示例中使用的标记),因此我们将查看该位置来定义视图的相对位置。否则寻呼机中的子订单是混合的
      • 必须在适配器内填充第一次绝对视图。 (其余时间此填充将无效)找不到强制它从寻呼机处理程序填充的方法。休息时间绝对视图将被具有正确值的寻呼机处理程序覆盖。
      • 当页面快速滑动时,页面(实际上是左侧)不会从页面处理程序中填充。暂时没有解决方法,只使用空视图,当拖动停止时它将填充实际值。 upd:快速解决方法:禁用适配器的 destroyItem。

      您可以查看 logcat 以了解此示例中发生的情况

      <?xml version="1.0" encoding="utf-8"?>
      <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:layout_width="match_parent"
          android:layout_height="match_parent" >
      
          <TextView xmlns:android="http://schemas.android.com/apk/res/android"
              android:id="@+id/calendar_text"
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:textSize="20sp"
              android:padding="5dp"
              android:layout_gravity="center_horizontal"
              android:text="Text Text Text"
          />
      
      </RelativeLayout>
      

      然后:

      public class ActivityCalendar extends Activity
      {
          public class CalendarAdapter extends PagerAdapter
          {
              @Override
              public int getCount()
              {
                  return 3;
              }
      
              @Override
              public boolean isViewFromObject(View view, Object object)
              {
                  return view == ((RelativeLayout) object);
              }
      
              @Override
              public Object instantiateItem(ViewGroup container, int position)
              {
                  LayoutInflater inflater = (LayoutInflater)ActivityCalendar.this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                  View viewLayout = inflater.inflate(R.layout.layout_calendar, container, false);
                  viewLayout.setTag(new Integer(position));
      
                  //TextView tv = (TextView) viewLayout.findViewById(R.id.calendar_text);
                  //tv.setText(String.format("Text Text Text relative: %d", position));
      
                  if (!ActivityCalendar.this.scrolledOnce)
                  {
                      // fill here only first time, the rest will be overriden in pager scroll handler
                      switch (position)
                      {
                          case 0:
                              ActivityCalendar.this.setPageContent(viewLayout, globalPosition - 1);
                              break;
                          case 1:
                              ActivityCalendar.this.setPageContent(viewLayout, globalPosition);
                              break;
                          case 2:
                              ActivityCalendar.this.setPageContent(viewLayout, globalPosition + 1);
                              break;
                      }
                  }
      
                  ((ViewPager) container).addView(viewLayout);
      
                  //Log.i("instantiateItem", String.format("position = %d", position));
      
                  return viewLayout;
              }
      
              @Override
              public void destroyItem(ViewGroup container, int position, Object object)
              {
                  ((ViewPager) container).removeView((RelativeLayout) object);
      
                  //Log.i("destroyItem", String.format("position = %d", position));
              }
          }
      
          public void setPageContent(View viewLayout, int globalPosition)
          {
              if (viewLayout == null)
                  return;
              TextView tv = (TextView) viewLayout.findViewById(R.id.calendar_text);
              tv.setText(String.format("Text Text Text global %d", globalPosition));
          }
      
          private boolean scrolledOnce = false;
          private int focusedPage = 0;
          private int globalPosition = 0;
      
          @Override
          public void onCreate(Bundle savedInstanceState)
          {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.activity_calendar);
      
              final ViewPager viewPager = (ViewPager) findViewById(R.id.pager);
      
              viewPager.setOnPageChangeListener(new OnPageChangeListener()
              {
                  @Override
                  public void onPageSelected(int position)
                  {
                      focusedPage = position;
                      // actual page change only when position == 1
                      if (position == 1)
                          setTitle(String.format("relative: %d, global: %d", position, globalPosition));
                      Log.i("onPageSelected", String.format("focusedPage/position = %d, globalPosition = %d", position, globalPosition));
                  }
      
                  @Override
                  public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels)
                  {
                      //Log.i("onPageScrolled", String.format("position = %d, positionOffset = %f", position, positionOffset));
                  }
      
                  @Override
                  public void onPageScrollStateChanged(int state)
                  {
                      Log.i("onPageScrollStateChanged", String.format("state = %d, focusedPage = %d", state, focusedPage));
                      if (state == ViewPager.SCROLL_STATE_IDLE)
                      {
                          if (focusedPage == 0)
                              globalPosition--;
                          else if (focusedPage == 2)
                              globalPosition++;
      
                          scrolledOnce = true;
      
                          for (int i = 0; i < viewPager.getChildCount(); i++)
                          {
                              final View v = viewPager.getChildAt(i);
                              if (v == null)
                                  continue;
      
                              // reveal correct child position
                              Integer tag = (Integer)v.getTag();
                              if (tag == null)
                                  continue;
      
                              switch (tag.intValue())
                              {
                                  case 0:
                                      setPageContent(v, globalPosition - 1);
                                      break;
                                  case 1:
                                      setPageContent(v, globalPosition);
                                      break;
                                  case 2:
                                      setPageContent(v, globalPosition + 1);
                                      break;
                              }
                          }
      
                          Log.i("onPageScrollStateChanged", String.format("globalPosition = %d", globalPosition));
      
                          viewPager.setCurrentItem(1, false);
                      }
                  }
              });
      
              CalendarAdapter calendarAdapter = this.new CalendarAdapter();
              viewPager.setAdapter(calendarAdapter);
      
              // center item
              viewPager.setCurrentItem(1, false);
          }
      }
      

      【讨论】:

        【解决方案7】:

        它被 CustomPagerAdapter黑了

        MainActivity.java

        import android.content.Context;
        import android.os.Handler;
        import android.os.Parcelable;
        import android.support.v4.app.FragmentPagerAdapter;
        import android.support.v4.app.FragmentStatePagerAdapter;
        import android.support.v4.view.PagerAdapter;
        import android.support.v4.view.ViewPager;
        import android.support.v7.app.AppCompatActivity;
        import android.os.Bundle;
        import android.util.Log;
        import android.view.LayoutInflater;
        import android.view.View;
        import android.view.ViewGroup;
        import android.widget.LinearLayout;
        import android.widget.TextView;
        import java.util.ArrayList;
        import java.util.List;
        
        public class MainActivity extends AppCompatActivity {
        
            private List<String> numberList = new ArrayList<String>();
            private CustomPagerAdapter mCustomPagerAdapter;
            private ViewPager mViewPager;
            private Handler handler;
            private Runnable runnable;
        
            @Override
            protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);
        
                numberList.clear();
                for (int i = 0; i < 10; i++) {
                numberList.add(""+i);
                }
        
                mViewPager = (ViewPager)findViewById(R.id.pager);
                mCustomPagerAdapter = new CustomPagerAdapter(MainActivity.this);
                EndlessPagerAdapter mAdapater = new EndlessPagerAdapter(mCustomPagerAdapter);
                mViewPager.setAdapter(mAdapater);
        
        
                mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
                    @Override
                    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        
                    }
        
                    @Override
                    public void onPageSelected(int position) {
                        int modulo = position%numberList.size();
                        Log.i("Current ViewPager View's Position", ""+modulo);
        
                    }
        
                    @Override
                    public void onPageScrollStateChanged(int state) {
        
                    }
                });
        
                handler = new Handler();
                runnable = new Runnable() {
                    @Override
                    public void run() {
        
                        mViewPager.setCurrentItem(mViewPager.getCurrentItem()+1);
                        handler.postDelayed(runnable, 1000);
                    }
                };
        
                handler.post(runnable);
        
            }
        
            @Override
            protected void onDestroy() {
                if(handler!=null){
                    handler.removeCallbacks(runnable);
                }
                super.onDestroy();
            }
        
            private class CustomPagerAdapter extends PagerAdapter {
        
                Context mContext;
                LayoutInflater mLayoutInflater;
        
                public CustomPagerAdapter(Context context) {
                    mContext = context;
                    mLayoutInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                }
        
                @Override
                public int getCount() {
                    return numberList.size();
                }
        
                @Override
                public boolean isViewFromObject(View view, Object object) {
                    return view == ((LinearLayout) object);
                }
        
                @Override
                public Object instantiateItem(ViewGroup container, int position) {
                    View itemView = mLayoutInflater.inflate(R.layout.row_item_viewpager, container, false);
        
                    TextView textView = (TextView) itemView.findViewById(R.id.txtItem);
                    textView.setText(numberList.get(position));
                    container.addView(itemView);
                    return itemView;
                }
        
                @Override
                public void destroyItem(ViewGroup container, int position, Object object) {
                    container.removeView((LinearLayout) object);
                }
            }
        
            private class EndlessPagerAdapter extends PagerAdapter {
        
                private static final String TAG = "EndlessPagerAdapter";
                private static final boolean DEBUG = false;
        
                private final PagerAdapter mPagerAdapter;
        
                EndlessPagerAdapter(PagerAdapter pagerAdapter) {
                    if (pagerAdapter == null) {
                        throw new IllegalArgumentException("Did you forget initialize PagerAdapter?");
                    }
                    if ((pagerAdapter instanceof FragmentPagerAdapter || pagerAdapter instanceof FragmentStatePagerAdapter) && pagerAdapter.getCount() < 3) {
                        throw new IllegalArgumentException("When you use FragmentPagerAdapter or FragmentStatePagerAdapter, it only supports >= 3 pages.");
                    }
                    mPagerAdapter = pagerAdapter;
                }
        
                @Override
                public void destroyItem(ViewGroup container, int position, Object object) {
                    if (DEBUG) Log.d(TAG, "Destroy: " + getVirtualPosition(position));
                    mPagerAdapter.destroyItem(container, getVirtualPosition(position), object);
        
                    if (mPagerAdapter.getCount() < 4) {
                        mPagerAdapter.instantiateItem(container, getVirtualPosition(position));
                    }
                }
        
                @Override
                public void finishUpdate(ViewGroup container) {
                    mPagerAdapter.finishUpdate(container);
                }
        
                @Override
                public int getCount() {
                    return Integer.MAX_VALUE; // this is the magic that we can scroll infinitely.
                }
        
                @Override
                public CharSequence getPageTitle(int position) {
                    return mPagerAdapter.getPageTitle(getVirtualPosition(position));
                }
        
                @Override
                public float getPageWidth(int position) {
                    return mPagerAdapter.getPageWidth(getVirtualPosition(position));
                }
        
                @Override
                public boolean isViewFromObject(View view, Object o) {
                    return mPagerAdapter.isViewFromObject(view, o);
                }
        
                @Override
                public Object instantiateItem(ViewGroup container, int position) {
                    if (DEBUG) Log.d(TAG, "Instantiate: " + getVirtualPosition(position));
                    return mPagerAdapter.instantiateItem(container, getVirtualPosition(position));
                }
        
                @Override
                public Parcelable saveState() {
                    return mPagerAdapter.saveState();
                }
        
                @Override
                public void restoreState(Parcelable state, ClassLoader loader) {
                    mPagerAdapter.restoreState(state, loader);
                }
        
                @Override
                public void startUpdate(ViewGroup container) {
                    mPagerAdapter.startUpdate(container);
                }
        
                int getVirtualPosition(int realPosition) {
                    return realPosition % mPagerAdapter.getCount();
                }
        
                PagerAdapter getPagerAdapter() {
                    return mPagerAdapter;
                }
        
            }
        }
        

        activity_main.xml

        <?xml version="1.0" encoding="utf-8"?>
        <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
            android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
            android:paddingRight="@dimen/activity_horizontal_margin"
            android:paddingTop="@dimen/activity_vertical_margin"
            android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">
        
            <android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
                android:id="@+id/pager"
                android:layout_width="match_parent"
                android:layout_height="180dp">
            </android.support.v4.view.ViewPager>
        
        </RelativeLayout>
        

        row_item_viewpager.xml

        <?xml version="1.0" encoding="utf-8"?>
        <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
            android:layout_width="match_parent" android:layout_height="match_parent"
            android:gravity="center">
        
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:id="@+id/txtItem"
                android:textAppearance="@android:style/TextAppearance.Large"/>
        
        </LinearLayout>
        

        完成

        【讨论】:

        • MAX_INTEGER 将使ArrayList&lt;ItemInfo&gt; mItemsViewPager 中增长。您还可以进一步滚动 - 调用 ViewPager.populate 的时间将增加,因为它会在 mItems 上循环查找当前位置的缓存 ItemInfo
        • 尝试使用FragmentStatePagerAdapter,它只保留前一个,当前和下一个三个片段,每次来回滚动适配器都会回收他的片段/布局。
        【解决方案8】:

        对于连续几天无限滚动,重要的是您在寻呼机中拥有良好的片段,因此我在页面上写下了我的答案 (Viewpager in Android to switch between days endlessly)

        效果很好!以上答案对我不起作用,因为我希望它起作用。

        【讨论】:

          【解决方案9】:

          我构建了一个库,可以使任何 ViewPager、pagerAdapter(或 FragmentStatePagerAdapter)和可选的 TabLayout 无限滚动。

          https://github.com/memorex386/infinite-scroll-viewpager-w-tabs

          【讨论】:

            【解决方案10】:

            基于https://github.com/antonyt/InfiniteViewPager 我写了这个效果很好:

            class InfiniteViewPager @JvmOverloads constructor(
              context: Context,
              attrs: AttributeSet? = null
            ) : ViewPager(context, attrs) {
              // Allow for 100 back cycles from the beginning.
              // This should be enough to create an illusion of infinity.
              // Warning: scrolling to very high values (1,000,000+) results in strange drawing behaviour.
              private val offsetAmount get() = if (adapter?.count == 0) 0 else (adapter as InfinitePagerAdapter).realCount * 100
            
              override fun setAdapter(adapter: PagerAdapter?) {
                super.setAdapter(if (adapter == null) null else InfinitePagerAdapter(adapter))
                currentItem = 0
              }
            
              override fun setCurrentItem(item: Int) = setCurrentItem(item, false)
            
              override fun setCurrentItem(item: Int, smoothScroll: Boolean) {
                val adapterCount = adapter?.count
            
                if (adapterCount == null || adapterCount == 0) {
                  super.setCurrentItem(item, smoothScroll)
                } else {
                  super.setCurrentItem(offsetAmount + item % adapterCount, smoothScroll)
                }
              }
            
              override fun getCurrentItem(): Int {
                val adapterCount = adapter?.count
            
                return if (adapterCount == null || adapterCount == 0) {
                  super.getCurrentItem()
                } else {
                  val position = super.getCurrentItem()
                  position % (adapter as InfinitePagerAdapter).realCount
                }
              }
            
              fun animateForward() {
                super.setCurrentItem(super.getCurrentItem() + 1, true)
              }
            
              fun animateBackwards() {
                super.setCurrentItem(super.getCurrentItem() - 1, true)
              }
            
              internal class InfinitePagerAdapter(private val adapter: PagerAdapter) : PagerAdapter() {
                internal val realCount: Int get() = adapter.count
            
                override fun getCount() = if (realCount == 0) 0 else Integer.MAX_VALUE
            
                override fun instantiateItem(container: ViewGroup, position: Int) = adapter.instantiateItem(container, position % realCount)
            
                override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) = adapter.destroyItem(container, position % realCount, `object`)
            
                override fun finishUpdate(container: ViewGroup) = adapter.finishUpdate(container)
            
                override fun isViewFromObject(view: View, `object`: Any) = adapter.isViewFromObject(view, `object`)
            
                override fun restoreState(bundle: Parcelable?, classLoader: ClassLoader?) = adapter.restoreState(bundle, classLoader)
            
                override fun saveState(): Parcelable? = adapter.saveState()
            
                override fun startUpdate(container: ViewGroup) = adapter.startUpdate(container)
            
                override fun getPageTitle(position: Int) = adapter.getPageTitle(position % realCount)
            
                override fun getPageWidth(position: Int) = adapter.getPageWidth(position)
            
                override fun setPrimaryItem(container: ViewGroup, position: Int, `object`: Any) = adapter.setPrimaryItem(container, position, `object`)
            
                override fun unregisterDataSetObserver(observer: DataSetObserver) = adapter.unregisterDataSetObserver(observer)
            
                override fun registerDataSetObserver(observer: DataSetObserver) = adapter.registerDataSetObserver(observer)
            
                override fun notifyDataSetChanged() = adapter.notifyDataSetChanged()
            
                override fun getItemPosition(`object`: Any) = adapter.getItemPosition(`object`)
              }
            }
            

            要使用它,只需将您的 ViewPager 更改为 InfiniteViewPager,这就是您需要更改的全部内容。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2023-03-12
              相关资源
              最近更新 更多