android – 修复循环ViewPager的动画

目标

构建一个循环ViewPager.

第一个元素可让您达到最后一个元素并向其滑动,反之亦然.你应该能够永远在任一方向滑动.

现在这已经在之前完成了,但这些问题对我的实现来说并不奏效.这里有几个参考:

> how to create circular viewpager?
> ViewPager as a circular queue / wrapping
> https://github.com/antonyt/InfiniteViewPager

我如何试图解决问题

我们将使用大小为7的数组作为示例.要点如下:

[0][1][2][3][4][5][6]

当您在元素0时,ViewPagers不允许您向左滑动!多么可怕:(为了解决这个问题,我在前面和结尾添加了1个元素.

   [0][1][2][3][4][5][6]      // Original
[0][1][2][3][4][5][6][7][8]   // New mapping

当ViewPageAdapter要求(instantiateItem())元素0时,我们返回元素7.当ViewPageAdapter要求元素8时,我们返回元素1.

同样在ViewPager中的OnPageChangeListener中,当onPageSelected被调用为0时,我们将setCurrentItem(7)调用,当我们使用8调用setCurrentItem(1)时.

这个工作.

问题

当您从1到0向左滑动,并且我们设置CurrentItem(7)时,它将通过6个全屏显示动画.这不给出一个循环ViewPager的外观,它给了用户以滑动运动方式向用户请求的方向冲击最后一个元素!

这非常非常震撼.

我如何试图解决这个问题

我的第一个倾向是关闭光滑(即所有)动画.这有点好一点,但是当你从最后一个元素移动到第一个元素时,它现在变得不稳定,反之亦然.

然后我自己做了滚轮.

http://developer.android.com/reference/android/widget/Scroller.html

我发现,在元素之间移动时总是有1次调用startScroll(),除非我从1到7和7移动到1.

第一个电话是方向和数量上的正确动画.

第二个调用是将多个页面向右移动的动画.

这是事情真的很棘手的地方.

我以为解决方案是跳过第二个动画.所以我做了.发生什么事情是一个平滑的动画从1到7与0打嗝.完善!但是,如果您滑动,甚至点击屏幕,您突然(没有动画)在元素6!如果你已经从7刷新到1,那么你实际上是在元素2.没有调用setCurrentItem(2),甚至没有调用OnPageChangeListener,表示你在任何时候到达了2.

但是实际上你并没有在元素2,这是一种好的.您仍然在元素1,但将显示元素2的视图.然后当你向左滑动时,你去元素1.即使你真的在元素1已经..一些代码如何帮助清除事情:

动画破碎,但没有奇怪的副作用

@Override
public void startScroll(int startX, int startY, int dx, int dy, int duration) {
    super.startScroll(startX, startY, dx, dy, duration);
}

动画作品!但一切都是奇怪和可怕的

@Override
public void startScroll(int startX, int startY, int dx, int dy, int duration) {
    if (dx > 480 || dx < -480) {
    } else {
        super.startScroll(startX, startY, dx, dy, duration);
    }
}

唯一的区别是当第二个动画(大于480像素屏幕的宽度)被调用时,我们忽略它.

在阅读了Scroller的Android源代码之后,我发现startScroll没有开始滚动任何东西.它设置所有要滚动的数据,但不启动任何内容.

我的希望

执行循环操作(1到7或7到1)时,有两个调用startScroll().我认为这两个电话之间的事情正在引起一个问题.

>用户从元素1滚动到元素7,导致从0到7的跳转.这应该向左动画.
> startScroll()被调用,表示左边的一个短的动画.
> STUFF HAPPENS,这使我想起了我的想法
> startScroll()被调用,表示右侧的长动画.
>发生右侧的长动画.

如果我发表评论4,那么5成为“左边的动画正确,事情变得疯狂”

概要

我的一个循环ViewPager的实现工作,但动画是坏的.尝试修复动画后,会破坏ViewPager的功能.我正在旋转我的车轮,试图找出如何使它的工作.帮我! 🙂

如果有什么不清楚,请在下面评论,我会澄清.我意识到,如果事情被破坏,我不是很精准.这很难描述,因为我甚至不清楚我在屏幕上看到的内容.如果我的解释是一个可以解决的问题,让我知道!

干杯,
Coltin

该代码稍作修改,使其更易于读取,尽管功能与我当前的代码迭代相同.

OnPageChangeListener.onPageSelected

@Override
public void onPageSelected(int _position) {
    boolean animate = true;
    if (_position < 1) {
        // Swiping left past the first element, go to element (9 - 2)=7
        setCurrentItem(getAdapter().getCount() - 2, animate);
    } else if (_position >= getAdapter().getCount() - 1) {
        // Swiping right past the last element
        setCurrentItem(1, animate);
    }
}

CircularScroller.startScroll

@Override
public void startScroll(int _startX, int _startY, int _dx, int _dy, int _duration) {
    // 480 is the width of the screen
    if (dx > 480 || dx < -480) {
        // Doing nothing in this block shows the correct animation,
        // but it causes the issues mentioned above

        // Uncomment to do the big scroll!
        // super.startScroll(_startX, _startY, _dx, _dy, _duration);

        // lastDX was to attempt to reset the scroll to be the previous
        // correct scroll distance; it had no effect
        // super.startScroll(_startX, _startY, lastDx, _dy, _duration);
    } else {
        lastDx = _dx;
        super.startScroll(_startX, _startY, _dx, _dy, _duration);
    }
}

CircularViewPageAdapter.CircularViewPageAdapter

private static final int m_Length = 7; // For our example only
private static Context m_Context;
private boolean[] created = null; // Not the best practice..

public CircularViewPageAdapter(Context _context) {
    m_Context = _context;
    created = new boolean[m_Length];
    for (int i = 0; i < m_Length; i++) {
        // So that we do not create things multiple times
        // I thought this was causing my issues, but it was not
        created[i] = false;
    }
}

CircularViewPageAdapter.getCount

@Override
public int getCount() {
    return m_Length + 2;
}

CircularViewPageAdapter.instantiateItem

@Override
public Object instantiateItem(View _collection, int _position) {

    int virtualPosition = getVirtualPosition(_position);
    if (created[virtualPosition - 1]) {
        return null;
    }

    TextView tv = new TextView(m_Context);
    // The first view is element 1 with label 0! :)
    tv.setText("Bonjour, merci! " + (virtualPosition - 1));
    tv.setTextColor(Color.WHITE);
    tv.setTextSize(30);

    ((ViewPager) _collection).addView(tv, 0);

    return tv;
}

CircularViewPageAdapter.destroyItem

@Override
public void destroyItem(ViewGroup container, int position, Object view) {
    ViewPager viewPager = (ViewPager) container;
    // If the virtual distance is distance 2 away, it should be destroyed.
    // If it's not intuitive why this is the case, please comment below
    // and I will clarify
    int virtualDistance = getVirtualDistance(viewPager.getCurrentItem(), getVirtualPosition(position));
    if ((virtualDistance == 2) || ((m_Length - virtualDistance) == 2)) {
        ((ViewPager) container).removeView((View) view);
        created[getVirtualPosition(position) - 1] = false;
    }
}
我认为最好的可行方法是使用普通列表来替代List,当get(pos)方法被执行来获取对象来创建视图时,你可以做这样的get(pos%numberOfViews ),并且当它要求列表的大小时,您将列表列为Integer.MAX_VALUE,并且您在其中间启动列表,所以您可以说这几乎不可能有错误,除非他们实际上刷到同一个一直到到达列表的末尾.如果时间允许我这样做,我会尝试发布概念证明.

编辑:

我已经尝试了这段代码,我知道每个视图都显示一个简单的文本框,但事实是它的工作原理很好,它可能会更慢,这取决于视图的总数,但概念证明在这里.我所做的是MAX_NUMBER_VIEWS代表用户在停止之前最多可以完全提供的次数.并且您可以看到我在我的阵列长度上启动了查看器,这样它就是第二次出现,所以你有一个额外的向左和向右,但你可以根据需要改变它.我希望我没有得到更多的负面点,一个解决方案实际上是有效的.

活动:

pager = (ViewPager)findViewById(R.id.viewpager);
String[] articles = {"ARTICLE 1","ARTICLE 2","ARTICLE 3","ARTICLE 4"};
pager.setAdapter(new ViewPagerAdapter(this, articles));
pager.setCurrentItem(articles.length);

适配器:

public class ViewPagerAdapter extends PagerAdapter {

private Context ctx;
private String[] articles;
private final int MAX_NUMBER_VIEWS = 3;

public ViewPagerAdapter(Context ctx, String[] articles) {
    this.ctx = ctx;
    this.articles = articles.clone();
}

@Override
public int getCount() {
    return articles.length * this.MAX_NUMBER_VIEWS;
}

@Override
public Object instantiateItem(ViewGroup container, int position) {
    TextView view = new TextView(ctx);
    view.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
                                          LayoutParams.MATCH_PARENT));
    int realPosition = position % articles.length;
    view.setText(this.articles[realPosition]);
    ((ViewPager) container).addView(view);
    return view;
}

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

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

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

}
http://stackoverflow.com/questions/11622544/fix-the-animation-of-a-circular-viewpager

本站文章除注明转载外,均为本站原创或编译
转载请明显位置注明出处:android – 修复循环ViewPager的动画