【问题标题】:Android ViewPager: Move any page to end programatically?Android ViewPager:移动任何页面以编程方式结束?
【发布时间】:2012-09-07 15:59:17
【问题描述】:

在 Android 中使用Viewpager,是否可以以编程方式将任何页面移动到末尾?例如,我有 5 页,想将第 2 页移动到最后一个位置(第 5 个位置),所以第 3 页变成 2,第 4 页变成 3,第 5 页变成 4?

谢谢

【问题讨论】:

    标签: android-viewpager


    【解决方案1】:

    是的。我将尝试通过展示我是如何做到的来回答您的案例,我将在我的代码示例下方展示您案例的示例。

    基本上,要做到这一点,您必须跟踪片段的位置。下面是我为 FragmentPagerAdapter 使用的实现,它使用 ArrayList 作为其数据源。

    public class MyFragmentPagerAdapter extends FragmentPagerAdapter {
    
        private HashMap<Long, Fragment> mItems
                        = new HashMap<Long, Fragment>();
    
        private ArrayList<MyObject> dataset;
    
        public MyFragmentPagerAdapter(ArrayList<MyObject> objects) {
            this.dataset = objects;
        }
    
        @Override
        public int getCount() {
            return dataset.size();
        }
    
        @Override
        public Fragment getItem(int position) {
            long id = getItemId(position);
    
            if(mItems.get(id) != null) {
                // caching to prevent multiple instances of the same fragment
                // for the same position/id
                return mItems.get(id);
            }
    
            Fragment f = Fragment.newInstance();
    
            mItems.put(id, f);
    
            return f;
        }
    
        @Override
        public long getItemId(int position) {
            // return a unique id
            return dataset.get(position).getUniqueId();
        }
    
        @Override
        public int getItemPosition(Object object) {
            /*
             * Purpose of this method is to check whether an item in the adapter
             * still exists in the dataset and where it should show.
             * For each entry in dataset, request its Fragment.
             * 
             * If the Fragment is found, return its (new) position. There's
             * no need to return POSITION_UNCHANGED; ViewPager handles it.
             * 
             * If the Fragment passed to this method is not found, remove all
             * references and let the ViewPager remove it from display by
             * by returning POSITION_NONE;
             */
            Fragment f = (Fragment) object;
    
            for(int i = 0; i < getCount(); i++) {
    
                Fragment item = (Fragment) getItem(i);
                if(item.equals(f)) {
                    // item still exists in dataset; return position
                    return i;
                }
            }
    
            // if we arrive here, the data-item for which the Fragment was created
            // does not exist anymore.
    
            // Also, cleanup: remove reference to Fragment from mItems
            for(Map.Entry<Long, MainListFragment> entry : mItems.entrySet()) {
                if(entry.getValue().equals(f)) {
                    mItems.remove(entry.getKey());
                    break;
                }
            }
    
            // Let ViewPager remove the Fragment by returning POSITION_NONE.
            return POSITION_NONE;
        }
    }
    

    现在,如果您从数据集 (this.dataset) 中删除一个项目并在您的 MyFragmentPagerAdapter 实例上调用 notifyDataSetChanged(),它将从 ViewPager 中删除该项目(即使它当前正在被查看)。

    假设this.dataset 包含5 个项目,并且您想将#2 移动到ViewPager 的末尾。为此,您必须将 item#2 定位到数据源的末尾(通过Collection.Sort 或其他方式)。我将向您展示简单的方法。

    ArrayList<MyObject> list = new ArrayList<>();
    MyFragmentPagerAdapter adapter = new MyFragmentPagerAdapter(list);
    viewpager.setAdapter(adapter);
    
    ...
    
    MyObject item = list.get(2);
    list.remove(item);
    list.add(item); // now it's positioned at the end of the list
    adapter.notifyDataSetChanged(); // voilá, that should do the trick!
    

    adapter.notifyDataSetChanged() 最终调用viewpager.dataSetChanged(),而后者又在其每个页面上调用adapter.getItemPosition(..)。该方法调用的结果决定了页面(本例中为 Fragment)是否以及在何处显示。

    【讨论】:

    • 非常容易理解。为什么您不使用 FragmentStatePagerAdapter 与此实现?你的 mItems 列表会让大型课程失去所有可用性的理由吗?
    • 这似乎也没有帮助我。我正在删除项目,完全。每当我转到下一个项目,删除前一个项目时,它会滑动但在中间滑动时将下一个项目更改为之后的项目。视觉上:适配器视图 A 中的 A、B、C 项目,滑动到 B。开始删除 A,中间滑动到 B,Flash 到 C。
    • 是的,这是意料之中的。如果删除 A,B 将是 pos==0,C 是 pos==1。从 A 滑动到 B 时,您当前的项目 (viewPager.setCurrentItem(int)) 设置为 1。当您移除 A 时,当前位置仍为 1,这意味着 ViewPager 将跳转到 C。您可以通过设置 @987654334 来纠正此问题@当你删除 A 时。
    • +1 很好的解决方案。具有唯一 ID 的 getItemId(int position) 对我有用。
    • @Ewanw 现在应该修复了,我想我在输入第二个片段时没有注意。
    【解决方案2】:

    我刚刚阅读了所有这些内容。

    使用 ViewPager 的常用方法是使用 PagerAdapter 类,在正确的时刻为其提供正确的页面。 PagerAdapter、FragmentPagerAdapter 和 FragmentStatePagerAdapter 有很好的子类,它们更易于使用。

    但是,为了能够更改页面顺序,您将不得不编写自己的 PagerAdapter 子类。基本上,ViewPager 有两种方法知道您在哪个页面上:页码和适配器给它的关键对象。因此,您应该能够在 ViewPager 不会太丢失的情况下更改顺序。

    如何完成的血腥细节在this page 上。我还没有尝试过,但我会在接下来的几周内尝试。我认为该页面并不能说明一切。它没有提到大多数适配器类必须具有的 getItem() 方法。所以我真的还没有看到这些页面是如何添加到 ViewPager 中的。

    是时候查找和阅读一些示例代码了。

    【讨论】:

      猜你喜欢
      • 2015-05-12
      • 2015-07-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-05
      • 1970-01-01
      • 2014-01-24
      • 1970-01-01
      相关资源
      最近更新 更多