【问题标题】:ViewPager as a circular queue / wrappingViewPager 作为循环队列/包装
【发布时间】:2011-09-25 14:42:19
【问题描述】:

我使用ViewPagerFragmentStatePagerAdapter 来允许在一些片段之间导航。

假设我有三个片段:ABC。 ViewPager 最初显示 Fragment A,并允许您通过从右向左滑动导航到 Fragment B,然后通过再次滑动导航到 Fragment C。这允许以下导航路径:A <--> B <--> C

我想要的是能够在 Fragment A 上从左向右滑动,并让 ViewPager 显示 Fragment C,即让它表现为一个循环队列并允许... --> C <--> A <--> B <--> C <--> A <-- ...

我不希望片段在其他位置重复(即以三个以上的实例结束)。

ViewPager 可以实现这种包装功能吗?

【问题讨论】:

  • 它不是ViewPager 内置的,但您可以尝试修改FragmentStatePagerAdapter.instantiateItem 以使用一些模数数学来加载正确的片段。您需要覆盖 getCount 以返回足够大的数字。
  • @antonyt 你找到解决办法了吗?
  • @BryanDenny 还没有,我现在实际上已经将我的应用程序转换为不同的设计。如果我得到原始问题的有效解决方案,我会回复。
  • 您找到解决方案了吗?
  • @Enigma 请在下面查看我的回答。

标签: android android-fragments android-viewpager


【解决方案1】:

我已经实现了一个 ViewPager/PagerAdapter,它可以允许伪无限分页行为。它通过指定一个非常大的数字作为实际计数来工作,但将它们映射到数据集/页面集的实际范围。它还会将开头偏移一个很大的数字,以便您可以立即从“第一”页向左滚动。

当您到达第 1,000,000 页时,它就不能很好地工作了(滚动时您会看到图形故障),但这通常不是真实世界的用例。我可以通过不时将计数重置为较低的数字来解决此问题,但我将暂时保留它的状态。

InfinitePagerAdapter 包装了现有的 ViewPager,因此使用非常透明。 InfiniteViewPager 确实做了一些工作,以确保您可以多次向左和向右滚动。

https://github.com/antonyt/InfiniteViewPager

【讨论】:

  • 哇,这太棒了。我把它做成了一个伪无限(实际上是 365)寻呼机。现在使用 TitlePageIndicator 进行测试。非常感谢
  • 太棒了..哈哈!为什么我没有想到...肯定+1
  • 页数小于4时有问题。
  • 你好,安东尼。如何修复少于 4 个碎片?我在这里看到了你的答案github.com/antonyt/InfiniteViewPager/issues/2你能帮我吗?我需要交换 3 个片段,但我无法修复此错误。如何阻止 destroyItem() / 调用 instantiateItem() ?
  • java.lang.IllegalStateException:已添加片段:我得到了那个异常。我使用的页面少于 3 页。
【解决方案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 的“末尾”出现这种蓝色光芒,您应该将此行应用于放置 ViewPager 的 xml:

android:overScrollMode="never"

我们改进了上述解决方案并在github 上创建了一个小库。请随意查看:)

Edit:: 根据@Bhavana 的评论,只需使用 addOnPageChangeListener 而不是 setOnPageChangeListener,因为稍后已弃用。

 viewPager.addOnPageChangeListener(new CircularViewPagerHandler(viewPager));

【讨论】:

  • 又好又简单,就是不滑动
  • 对我来说效果很好,我在 Github 上关注了这个项目。非常感谢。
  • 真的是一个很好的帮助... tysm :)
  • 也为我工作,谢谢!!
  • 完美运行..!!只需使用 addOnPageChangeListener 而不是 setOnPageChangeListener ,因为稍后已弃用.. 谢谢..
【解决方案3】:

我一直在尝试所有建议、解决方案、库等,但它们不是纯循环的,而且大多数时候不支持仅 3 页。

所以我使用新的ViewPager2 实现了一个循环ViewPager 示例,新的ViewPager 使用RecyclerViewViewHolders 来处理视图回收并按预期工作!

TLDR: GITHUB

在此示例中,将构建一个带有 ViewPager2FragmentPagerAdapter 的单个活动应用程序,支持 3 个或更多页面之间的循环导航。

我正在使用库 androidx.viewpager2:viewpager2 的 alpha 版本,但 1.0.0-alpha06 是在 google 冻结 API 并转为 beta 之前计划的最后一个版本。

1.将 ViewPager2 库添加到 build.gradle 中的依赖项

dependencies {
    implementation 'androidx.viewpager2:viewpager2:1.0.0-alpha06'
}

2。将ViewPager2 视图添加到您的项目中:

<androidx.viewpager2.widget.ViewPager2 xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/vwpHome"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

3.创建FragmentStateAdapter 适配器:

getItemCount()需要返回一个huuuuge数字。 (2147483647)

getCenterPage() 根据 huuuuge 号返回中心页面。 该方法用于获取ViewPager2中设置的初始页面位置,此时用户需要滑动~1073741823次才能到达ViewPager2的末尾。

class CircularPagerAdapter(fragmentManager: FragmentManager, lifecycle: Lifecycle) : FragmentStateAdapter(fragmentManager, lifecycle) {

    override fun getItemCount() = Integer.MAX_VALUE

    /**
     * Create the fragment based on the position
     */
    override fun createFragment(position: Int) = HomePagerScreens.values()[position % HomePagerScreens.values().size].fragment.java.newInstance()

    /**
     * Returns the same id for the same Fragment.
     */
    override fun getItemId(position: Int): Long = (position % HomePagerScreens.values().size).toLong()

    fun getCenterPage(position: Int = 0) = Integer.MAX_VALUE / 2 + position
}

HomeScreens 是一个包含页面信息的 ENUM。

enum class HomePagerScreens(@StringRes val title: Int,
                            val fragment: KClass<out Fragment>) {

    HOME_1(R.string.home_1, FragmentHome::class),
    HOME_2(R.string.home_2, FragmentHome::class),
    HOME_3(R.string.home_3, FragmentHome::class)
}

4.将适配器设置为 ViewPager

val circularAdapter = CircularPagerAdapter(supportFragmentManager, lifecycle)
vwpHome.apply {
    adapter = circularAdapter
    setCurrentItem(circularAdapter.getCenterPage(), false)
}

【讨论】:

  • 在我看来,这应该是唯一被接受的答案。非常感谢,@extmkv! :)
  • 嗨。当我尝试设置 getItemCount() = Integer.MAX_VALUE 时,我无法进入包含 viewpager 的屏幕。没有logcat所以我不知道发生了什么
【解决方案4】:

刚刚看到这个问题,找到了解决办法。 Solution Link

对 onPageScrollStateChanged 函数进行以下更改。假设您有 4 个标签。

private int previousState, currentState;

public void onPageScrollStateChanged(int state) {              

            int currentPage = viewPager.getCurrentItem();       //ViewPager Type
            if (currentPage == 3 || currentPage == 0){
                previousState = currentState;
                currentState = state;
                if (previousState == 1 && currentState == 0){

                    viewPager.setCurrentItem(currentPage == 0 ? 3 : 0);

                }

            }

        }

如果 state 变量在现有选项卡中,则其值为 1。

当您尝试您的第一个标签页或您的最后一个标签页进行导航时,它会变为 0。因此,比较之前和当前的状态,如代码所示,您就完成了。

见 onPageScrollStateChanged 函数here

希望对你有帮助。

【讨论】:

    【解决方案5】:

    另一种方法是将视图分页器中第一个元素的假副本添加到适配器的末尾,并将最后一个元素的假副本添加到开头。然后,当您在视图分页器中查看第一个/最后一个元素时,无需动画即可更改页面。

    所以基本上,您的视图分页器中的第一个/最后一个元素是假的,只是为了产生正确的动画,然后切换到结束/开始。 示例:

    list.add(list.get(0)); //add the first item again as the last, to create the wrap effect
    list.add(0, list.get(list.size()-2)); //insert a copy of the last item as the new first item, so we can scroll backwards too
    
    viewPager.setAdapter(list);
    viewPager.setCurrentItem(1, false); //default to the second element (because the first is now a fake)
    
    viewPager.setOnPageChangeListener(new OnPageChangeListener() {
    private void handleScrollState(final int state) {
            if (state == ViewPager.SCROLL_STATE_IDLE) { //this is triggered when the switch to a new page is complete
                final int lastPosition = viewPager.getAdapter().getCount() - 1;
                if (currentPosition == lastPosition) {
                    viewPager.setCurrentItem(1, false); //false so we don't animate
                } else if (currentPosition == 0) {
                    viewPager.setCurrentItem(lastPosition -1, false);
                }
            }
    
    }
    

    【讨论】:

    • 效果很好。简单而干净的解决方案。
    • 但是,如果您有无限滚动和自定义 PageTransformer 转换,您可能会遇到一些错误。在没有动画的情况下进行转换后,某些转换会破坏特定视图(例如 viewPager.setCurrentItem(1, false); )。尽管如此,如果你有一个简单的寻呼机,它就可以工作。
    【解决方案6】:

    这几乎完成了安东尼想要的,但它不会让你从 A -> C 走。 (没有经过大力测试,但似乎工作得很好)

    public class MyAdapter extends PagerAdapter {
        private List<Object> mItems;
        private int mFakeCount = 0;
    
        public MyAdapter(Context context, List<Object> items) {
            mItems = items;
            mFakeCount = mItems.size()+1;
        }
    
        @Override
        public int getCount() {
            return mFakeCount;
        }
    
        @Override
        public Object instantiateItem(View collection, int position) {
            // make the size larger, and change the position
            // to trick viewpager into paging forever
            if (position >= mItems.size()-1) {
                int newPosition = position%mItems.size();
    
                position = newPosition;
                mFakeCount++;
            }
    
            // do your layout inflating and what not here.
            // position will now refer to a correct index into your mItems list
            // even if the user has paged so many times that the view has wrapped
        }
    }
    

    【讨论】:

    • 如果您在设置适配器后调用viewPager.setCurrentItem((int) (adapter.getCount()/2), false);,它将让您从 A -> C 出发。这样,您的 ViewPager 将初始化到中间位置,因此您可以双向滚动。
    • 我很困惑这对你们有用。它对我不起作用... [AndroidRuntime] FATAL EXCEPTION: main [AndroidRuntime] java.lang.IllegalStateException: 应用程序的 PagerAdapter 在没有调用 PagerAdapter#notifyDataSetChanged 的​​情况下更改了适配器的内容!预期的适配器项目数:4,找到:5 寻呼机 ID:com.rpr.mobile:id/ambient_pager 寻呼机类:android.support.v4.view.ViewPager 有问题的适配器:rpr.mobile.droid.adapters.ambient.AmbientPagerAdapter 类[AndroidRuntime] 在 android.support.v4.view.ViewPager.populate(ViewPager.java:962)
    【解决方案7】:

    简单的想法如何实现这一点。当您的数组带有页面时,只需将此数组添加到正好位于中间的另一个数组中。

    例如,您有一个包含 15 个元素的数组。所以把它放到中间400个元素的数组中(200个位置)

    接下来只需向左右填充数组,这样您就可以四处移动了。

    示例图片:

    它看起来怎么样?

    https://youtu.be/7up36ylTzXk

    让代码说话:)

    https://gist.github.com/gelldur/051394d10f6f98e2c13d

    public class CyclicPagesAdapter extends FragmentStatePagerAdapter {
    
        public CyclicPagesAdapter(FragmentManager fm) {
            super(fm);
        }
    
        @Override
        public Fragment getItem(int position) {
            return _fragments.get(position).createInstance();
        }
    
        @Override
        public int getCount() {
            return _fragments.size();
        }
    
        public void addFragment(FragmentCreator creator) {
            _fragments.add(creator);
        }
    
        public interface FragmentCreator {
            Fragment createInstance();
        }
    
        public void clear() {
            _fragments.clear();
        }
    
        public void add(FragmentCreator fragmentCreator) {
            _fragments.add(fragmentCreator);
        }
    
        public void finishAdding() {
            ArrayList<FragmentCreator> arrayList = new ArrayList<>(Arrays.asList(new FragmentCreator[MAX_PAGES]));
            arrayList.addAll(MAX_PAGES / 2, _fragments);
    
            int mrPointer = _fragments.size() - 1;
            for (int i = MAX_PAGES / 2 - 1; i > -1; --i) {
                arrayList.set(i, _fragments.get(mrPointer));
                --mrPointer;
                if (mrPointer < 0) {
                    mrPointer = _fragments.size() - 1;
                }
            }
    
            mrPointer = 0;
            for (int i = MAX_PAGES / 2 + _fragments.size(); i < arrayList.size(); ++i) {
                arrayList.set(i, _fragments.get(mrPointer));
                ++mrPointer;
                if (mrPointer >= _fragments.size()) {
                    mrPointer = 0;
                }
            }
            _fragmentsRaw = _fragments;
            _fragments = arrayList;
        }
    
        public int getStartIndex() {
            return MAX_PAGES / 2;
        }
    
        public int getRealPagesCount() {
            return _fragmentsRaw.size();
        }
    
        public int getRealPagePosition(int index) {
            final FragmentCreator fragmentCreator = _fragments.get(index);
            for (int i = 0; i < _fragmentsRaw.size(); ++i) {
                if (fragmentCreator == _fragmentsRaw.get(i)) {
                    return i;
                }
            }
            //Fail...
            return 0;
        }
    
        private static final int MAX_PAGES = 500;
        public ArrayList<FragmentCreator> _fragments = new ArrayList<>();
        public ArrayList<FragmentCreator> _fragmentsRaw;
    }
    

    【讨论】:

    • 非常好的和干净的解决方案。谢谢你。我只有一个问题。为什么你决定使用接口来添加片段?通过例如addFragment(Fragment fragment) 的fanction 添加它们不是更容易吗?然后拿着一个片段列表?
    • @user3448282 我不想在内存中存储大量碎片,所以我进行延迟初始化。
    • 如果这不是问题,我想再问你一个问题。删除一个项目怎么样?这种方法是:pastebin.com/VKkY4j6Z 好吗?现在我收到java.util.ConcurrentModificationException 错误,所以这可能不是最佳解决方案。
    • @user3448282 没问题,但您必须以其他方式将其删除。在迭代期间,您的迭代器将在您删除时格式错误。只需stackoverflow.com/q/223918/1052261
    • 我有最后一个问题。你知道如何正确地从适配器中移除物品吗?我想删除一个项目,然后跳转到下一个项目(例如,我要删除项目编号 6/30,然后下一个显示的项目应该是 6/29)。我知道我应该从fragments 列表中删除所有项目。在notifyDataSetChanged 之后,将选择错误的项目,因为整个索引已更改。我的想法是计算在已删除项目的“左侧”删除了多少项目,然后滚动到 position - numberOfRemovedItemsOnLeft,但它在某些情况下有效,在某些情况下无效。
    【解决方案8】:

    我有一个我相信会奏效的解决方案。它没有经过测试,但在这里:

    FragmentPagerAdapter 作为超类的包装器:

    public abstract class AFlexibleFragmentPagerAdapter extends
            FragmentPagerAdapter
    {
        public AFlexibleFragmentPagerAdapter(FragmentManager fm)
        {
            super(fm);
            // TODO Auto-generated constructor stub
        }
    
        public abstract int getRealCount();
    
        public abstract int getStartPosition();
    
        public abstract int transformPosition(int position);
    };
    

    那么标准的 FragmentPagerAdapter 实现子类化这个新的抽象类:

    public class SomeFragmentPagerAdapter extends
            AFlexibleFragmentPagerAdapter
    {
    
        private Collection<Fragment> someContainer;
    
        public SomeFragmentPagerAdapter(FragmentManager fm, Container<Fragment> fs)
        {
            super(fm);
            someContainer = fs;
        }
    
        @Override
        public int getRealCount() { return someContainer.size(); }
    
        @Override
        public int getStartPosition() { return 0; }
    
        @Override
        public int transformPosition(int position) { return position; }
    };
    

    还有 Cyclic Pager Adapter 实现。

    public class SomeCyclicFragmentPagerAdapter extends
            SomeFragmentPagerAdapter 
    {
        private int realCount = 0;
        private int dummyCount = 0;
        private static final int MULTI = 3;
    
        public SomeFragmentPagerAdapter(FragmentManager fm, ...)
        {
            super(fm);
            realCount = super.getCount();
            dummyCount *= MULTI;
        }
    
        @Override
        public int getCount() { return dummyCount; }
    
        @Override
        public int getRealCount() { return realCount; }
    
        @Override
        public int getStartPosition() { return realCount; }
    
        @Override
        public int transformPosition(int position)
        {
            if (position < realCount) position += realCount;
            else if (position >= (2 * realCount)) position -= realCount;
    
            return position;
        }
    };
    

    ViewPager 初始化

        this.mViewPager.setCurrentItem(this.mPagerAdapter.getStartPosition());
    

    最后,回调实现:

        @Override
        public void onPageSelected(int position)
        {
            this.mTabHost.setCurrentTab(position % mPagerAdapter.getRealCount());
            this.mViewPager.setCurrentItem(this.mPagerAdapter
                    .transformPosition(position));
        }
    
        @Override
        public void onTabChanged(String tabId)
        {
            int pos = this.mTabHost.getCurrentTab();
    
            this.mViewPager.setCurrentItem(this.mPagerAdapter
                    .transformPosition(pos));
        }
    

    【讨论】:

      【解决方案9】:
      1. 为项目设置一些较大的值,例如 500000。
      2. 从适配器返回此值 * 实际项目数。
      3. 在 getItem(int i) 上将 i 调整为 -> i = i % 实际项目数。
      4. 在 onCreate(Bundle savedInstanceState) 上为页面 500000/2 设置当前项目

        public class MainActivity extends FragmentActivity {
        
            private final static int ITEMS_MAX_VALUE = 500000;
            private int actualNumCount = 10;
            private ViewPager mPager = null;
        
            private class OptionPageAdapter extends FragmentStatePagerAdapter {
                public OptionPageAdapter(FragmentManager fm) {
                    super(fm);
                }
        
                @Override
                public Fragment getItem(int i) {
                    try {
                        i = i % OptionType.values().length;
                        OptionPage optionPage = new OptionPage(i);
                        optionPage.id = i;
                        return optionPage;
                    } catch (Exception e) {
                        VayoLog.log(Level.WARNING, "Unable to create OptionFragment for id: " + i, e);
                    }
                    return null;
                }
        
                @Override
                public int getCount() {
                    return ITEMS_MAX_VALUE * actualNumCount;
                }
            }
        
            public static class OptionPage extends Fragment {
                private int id = 0
                @Nullable
                @Override
                public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
                    View mainView = inflater.inflate(R.layout.main_page, container, false);
                    return mainView;
                }
        
            }
        
            @Override
            public void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.main);
                mPager = (ViewPager) findViewById(R.id.main_pager);
                mPager.setOffscreenPageLimit(3);
                mPager.setAdapter(new OptionPageAdapter(this.getSupportFragmentManager()));
                mPager.setCurrentItem(ITEMS_MAX_VALUE/2,false);
        
            }
        
        }
        

      【讨论】:

        【解决方案10】:
        1. 在列表开头添加最后一个元素的假副本。
        2. 在末尾添加第一个元素的假副本。
        3. 在初始化代码中的某处选择真正的第一个元素:

              mViewPager.setCurrentItem(1);
          
        4. 修改setOnPageChangeListener:

              @Override
              public void onPageSelected(int state) {
                  if (state == ITEMS_NUMBER + 1) {
                      mViewPager.setCurrentItem(1, false);
                  } else if (state == 0) {
                      mViewPager.setCurrentItem(ITEMS_NUMBER, false);
                  }
              }
          

        【讨论】:

          【解决方案11】:

          基于this approach

          真正的循环,寻呼标题条,真正的无刷新滚动

          private static final int ITEM_NUM = 5 ; // 5 for smooth pager title strip
          private void addFragment(String title, String className) {
              if (fragments.size() < ITEM_NUM) {
                  Bundle b = new Bundle();
                  b.putInt("pos", fragments.size());
                  fragments.add(Fragment.instantiate(this, className, b));
          
              }
              titles.add(title);
              itemList.add(className);
          }
          

          查看页面适配器:

          public static class MyFragmentPageAdapter extends FragmentPagerAdapter {
          
              private HashMap<Long, Fragment> mItems = new HashMap<Long, Fragment>();
          
              public MyFragmentPageAdapter(FragmentManager fragmentManager) {
                  super(fragmentManager);
              }
          
              @Override
              public long getItemId(int position) {
                  int id = java.lang.System.identityHashCode(fragments.get(position));
                  return id;
              }
          
              @Override
              public Fragment getItem(int position) {
                  long id = getItemId(position);
                  if (mItems.get(id) != null) {
                      return mItems.get(id);
                  }
                  Fragment f = fragments.get(position);
                  return f;
              }
          
              @Override
              public int getCount() {
                  return ITEM_NUM;
              }
          
              @Override
              public CharSequence getPageTitle(int position) {
                  String t = titles.get(getItem(position).getArguments()
                          .getInt("pos"));
                  return t;
              }
          
              @Override
              public int getItemPosition(Object object) {
                  for (int i = 0; i < ITEM_NUM; i++) {
                      Fragment item = (Fragment) fragments.get(i);
                      if (item.equals((Fragment) object)) {
                          return i;
                      }
                  }
                  return POSITION_NONE;
              }
          }
          

          使用:

              itemList = new ArrayList<String>();
              fragments = new ArrayList<Fragment>();
              titles = new ArrayList<String>();
          
              addFragment("Title1", Fragment1.class.getName());
              ...
              addFragment("TitleN", FragmentN.class.getName());
          
              mAdapter = new MyFragmentPageAdapter(getSupportFragmentManager());
              mViewPager = (ViewPager) findViewById(R.id...);
          
              mViewPager.setAdapter(mAdapter);
              mViewPager.setCurrentItem(2);
              currPage = 2;
              visibleFragmentPos = 2;
          
              mViewPager.setOnPageChangeListener(new OnPageChangeListener() {
          
                  @Override
                  public void onPageSelected(int curr) {
                      dir = curr - currPage;
                      currPage = curr;
                  }
          
                  private void shiftRight() {
                      fragments.remove(0);
                      int pos = visibleFragmentPos + 3;
                      if (pos > itemList.size() - 1)
                          pos -= itemList.size();
                      if (++visibleFragmentPos > itemList.size() - 1)
                          visibleFragmentPos = 0;
                      insertItem(4, pos);
          
                  }
          
                  private void shiftLeft() {
                      fragments.remove(4);
                      int pos = visibleFragmentPos - 3;
                      if (pos < 0)
                          pos += itemList.size();
                      if (--visibleFragmentPos < 0)
                          visibleFragmentPos = itemList.size() - 1;
                      insertItem(0, pos);
                  }
          
                  private void insertItem(int datasetPos, int listPos) {
                      Bundle b = new Bundle();
                      b.putInt("pos", listPos);
                      fragments.add(datasetPos,
                              Fragment.instantiate(ctx, itemList.get(listPos), b));
                  }
          
                  @Override
                  public void onPageScrollStateChanged(int state) {
          
                      if (state == ViewPager.SCROLL_STATE_IDLE) {
                          if (dir == 1) {
                              shiftRight();
                          } else if (dir == -1) {
                              shiftLeft();
          
                          }
                          mAdapter.notifyDataSetChanged();
                          currPage = 2;
                      }
                  }
              });
          

          【讨论】:

            【解决方案12】:

            您可以使用来自https://github.com/pozitiffcat/cyclicview的简单视图
            特点之一是:

            不要重复第一个和最后一个视图,而是使用位图变体

            例子:

            public class MainActivity extends AppCompatActivity {
                @Override
                protected void onCreate(Bundle savedInstanceState) {
                    super.onCreate(savedInstanceState);
                    setContentView(R.layout.activity_main);
            
                    CyclicView cyclicView = (CyclicView) findViewById(R.id.cyclic_view);
                    cyclicView.setAdapter(new CyclicAdapter() {
                        @Override
                        public int getItemsCount() {
                            return 10;
                        }
            
                        @Override
                        public View createView(int position) {
                            TextView textView = new TextView(MainActivity.this);
                            textView.setText(String.format("TextView #%d", position + 1));
                            return textView;
                        }
            
                        @Override
                        public void removeView(int position, View view) {
                            // Do nothing
                        }
                    });
                }
            }
            

            【讨论】:

              【解决方案13】:

              抱歉耽搁了,但我已经看到了答案,我无法坚持,也必须回答:)。

              在您的适配器上,在 get count 方法上,执行以下操作:

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

              这行得通!

              【讨论】:

              • 为什么会这样? x % Integer.MAX_VALUE == x 对于任何 x
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2012-07-06
              • 1970-01-01
              • 2012-08-05
              • 2017-04-08
              • 2021-10-28
              • 2014-01-04
              相关资源
              最近更新 更多