改变ViewPager的转换速度和setCurrentItem

19

我有一个ViewPager,我想每5秒自动旋转一次,同时也允许用户滑动。然而,当我设置自动更改时,页面之间的过渡动画发生得非常快,我希望它变慢一些。

我在这里看到了这个问题的答案:

减缓安卓中 ViewPager 控制器的速度

但是他们都使用反射。是否有人知道在不使用反射的情况下减缓ViewPager的自动速度的任何方法?

我考虑使用PageTransformer,但不确定它是否可行,而且它可能会影响用户滑动的速度和自动旋转的速度吧?除非我可以某种方式检测到差异,然后执行一个或另一个PageTransformation

3个回答

41

使用此自定义View

public class ViewPagerCustomDuration extends ViewPager {
    private FixedSpeedScroller mScroller = null;

    public ViewPagerCustomDuration(Context context) {
        super(context);
        init();
    }

    public ViewPagerCustomDuration(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    /*
     * Override the Scroller instance with our own class so we can change the
     * duration
     */
    private void init() {
        try {
            Class<?> viewpager = ViewPager.class;
            Field scroller = viewpager.getDeclaredField("mScroller");
            scroller.setAccessible(true);
            mScroller = new FixedSpeedScroller(getContext(),
                    new DecelerateInterpolator());
            scroller.set(this, mScroller);
        } catch (Exception ignored) {
        }
    }

    /*
     * Set the factor by which the duration will change
     */
    public void setScrollDuration(int duration) {
        mScroller.setScrollDuration(duration);
    }

    private class FixedSpeedScroller extends Scroller {

        private int mDuration = 500;

        public FixedSpeedScroller(Context context) {
            super(context);
        }

        public FixedSpeedScroller(Context context, Interpolator interpolator) {
            super(context, interpolator);
        }

        public FixedSpeedScroller(Context context, Interpolator interpolator, boolean flywheel) {
            super(context, interpolator, flywheel);
        }

        @Override
        public void startScroll(int startX, int startY, int dx, int dy, int duration) {
            // Ignore received duration, use fixed one instead
            super.startScroll(startX, startY, dx, dy, mDuration);
        }

        @Override
        public void startScroll(int startX, int startY, int dx, int dy) {
            // Ignore received duration, use fixed one instead
            super.startScroll(startX, startY, dx, dy, mDuration);
        }

        public void setScrollDuration(int duration) {
            mDuration = duration;
        }
    }
}

3
我不确切地记得为什么我提出了这个问题或者我是如何解决它的,但是这个答案已经有足够多的赞同票,我愿意接受它作为正确答案。此外,@Ezio似乎认为它有效:D - Russ Wheeler
5
为什么至少不将兼容库中的组件设为可调节?现在已经是2018年了,我认为我们应该有能力自定义动画速度了... - Den Drobiazko
请注意,此类使用反射来访问 ViewPager 的内部字段。因此,在任何 Android 更新时都可能停止工作! - Lii
3
在你的问题文本中,你明确要求一个不使用反射的解决方案,而这个解决方案使用反射来访问一个私有字段。更糟糕的是,回答者甚至没有提到这一点。我认为你不应该接受这个答案。这个问题仍然是有效且未被回答的。 - Lii
这真是太糟糕了。 - John Sardinha
显示剩余2条评论

6

你需要创建自定义的视图翻页器。

import android.content.Context;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.widget.Scroller;

import java.lang.reflect.Field;

public class CustomViewPager extends ViewPager {

    private FixedSpeedScroller mScroller = null;
    private boolean enabled;

    public CustomViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.enabled = true;
        init();
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (this.enabled) {
            return super.onTouchEvent(event);
        }
        init();
        return false;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        if (this.enabled) {
            return super.onInterceptTouchEvent(event);
        }
        return false;
    }

    public void setPagingEnabled(boolean enabled) {
        this.enabled = enabled;
    }


    /*
     * Override the Scroller instance with our own class so we can change the
     * duration
     */
    private void init() {
        try {
            Class<?> viewpager = ViewPager.class;
            Field scroller = viewpager.getDeclaredField("mScroller");
            scroller.setAccessible(true);
            mScroller = new FixedSpeedScroller(getContext(),
                    new DecelerateInterpolator());
            scroller.set(this, mScroller);
        } catch (Exception ignored) {
        }
    }

    /*
     * Set the factor by which the duration will change
     */
    public void setScrollDuration(int duration) {
        mScroller.setScrollDuration(duration);
    }

    private class FixedSpeedScroller extends Scroller {

        private int mDuration = 500;

        public FixedSpeedScroller(Context context) {
            super(context);
        }

        public FixedSpeedScroller(Context context, Interpolator interpolator) {
            super(context, interpolator);
        }

        public FixedSpeedScroller(Context context, Interpolator interpolator, boolean flywheel) {
            super(context, interpolator, flywheel);
        }

        @Override
        public void startScroll(int startX, int startY, int dx, int dy, int duration) {
            // Ignore received duration, use fixed one instead
            super.startScroll(startX, startY, dx, dy, mDuration);
        }

        @Override
        public void startScroll(int startX, int startY, int dx, int dy) {
            // Ignore received duration, use fixed one instead
            super.startScroll(startX, startY, dx, dy, mDuration);
        }

        public void setScrollDuration(int duration) {
            mDuration = duration;
        }
    }

}

您可以根据自己的需要设置视图翻页器的持续时间。


1

使用计划定时器选项自动旋转页面。

int i = 0;
static Timer timer = new Timer();

//Scroller scroll = new Scroller(this);

@Override
protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    setContentView(R.layout.simple_circles);

    mAdapter = new TestFragmentAdapter(getSupportFragmentManager());

    mPager = (ViewPager) findViewById(R.id.pager);

    mPager.setAdapter(mAdapter);

     mIndicator = (CirclePageIndicator) findViewById(R.id.indicator);

    mIndicator.setViewPager(mPager);

    mPager.setCurrentItem(i);

    SwitchPage(3);


  }

public void SwitchPage(int seconds) 

{

if(timer != null)
{
    timer.cancel();
}

timer = new Timer(); // At this line a new Thread will be created

timer.schedule(new SwitchPageTask(), 
2000, seconds * 2000);               
 // delay in milliseconds
 }


class SwitchPageTask extends TimerTask 
{

@Override
public void run() {

    runOnUiThread(new Runnable() {

        public void run() {

            if(i < mAdapter.getCount())

            {

                i++;

                mPager.setCurrentItem(i, true);

            }
            else
            {

                i=0;

                mPager.setCurrentItem(i, true);
            }
        }
    });
}
}

just cancel the timer like.. timer.cancel().. or
cancel timer from another activity or fragment activity..

    textView1_page3.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {

                if (SampleCirclesDefault.timer != null) {
                    SampleCirclesDefault.timer.cancel();
                    Toast.makeText(getActivity(), "timer
                  cancled", 1).show();
                }

            }
        });

通过查看你的代码,我发现你正在改变转换之间的延迟时间。这不是我的问题所在。我认为自动转换的实际动画太快了,几乎是瞬间完成的,我希望它能更慢地从一张图片滚动到下一张,而不是有可变的时间差异。我会更新我的原始问题以使其更清晰明了。 - Russ Wheeler

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接