来源:http://www.trinea.cn/android/auto-scroll-view-pager/


1.实现方式

没有通过ScheduledExecutorService或Timer定期执行某个任务实现,而是简单的通过handler发送消息去完成一次滚动,在完成一次滚动后发送另外一个delay的滚动消息,如此循环实现。

2.自定义ViewPager

public class AutoScrollViewPager extends ViewPager {    public static final int        DEFAULT_INTERVAL            = 1500;    public static final int        LEFT                        = 0;    public static final int        RIGHT                       = 1;    /** do nothing when sliding at the last or first item **/    public static final int        SLIDE_BORDER_MODE_NONE      = 0;    /** cycle when sliding at the last or first item **/    public static final int        SLIDE_BORDER_MODE_CYCLE     = 1;    /** deliver event to parent when sliding at the last or first item **/    public static final int        SLIDE_BORDER_MODE_TO_PARENT = 2;    /** auto scroll time in milliseconds, default is {@link #DEFAULT_INTERVAL} **/    private long                   interval                    = DEFAULT_INTERVAL;    /** auto scroll direction, default is {@link #RIGHT} **/    private int                    direction                   = RIGHT;    /** whether automatic cycle when auto scroll reaching the last or first item, default is true **/    private boolean                isCycle                     = true;    /** whether stop auto scroll when touching, default is true **/    private boolean                stopScrollWhenTouch         = true;    /** how to process when sliding at the last or first item, default is {@link #SLIDE_BORDER_MODE_NONE} **/    private int                    slideBorderMode             = SLIDE_BORDER_MODE_NONE;    /** whether animating when auto scroll at the last or first item **/    private boolean                isBorderAnimation           = true;    private Handler                handler;    private boolean                isAutoScroll                = false;    private boolean                isStopByTouch               = false;    private float                  touchX                      = 0f, downX = 0f;    private CustomDurationScroller scroller                    = null;    public static final int        SCROLL_WHAT                 = 0;    public AutoScrollViewPager(Context paramContext) {        super(paramContext);        init();    }    public AutoScrollViewPager(Context paramContext, AttributeSet paramAttributeSet) {        super(paramContext, paramAttributeSet);        init();    }    private void init() {        handler = new MyHandler();        setViewPagerScroller();    }    /**     * start auto scroll, first scroll delay time is {@link #getInterval()}     */    public void startAutoScroll() {        isAutoScroll = true;        sendScrollMessage(interval);    }    /**     * start auto scroll     *     * @param delayTimeInMills first scroll delay time     */    public void startAutoScroll(int delayTimeInMills) {        isAutoScroll = true;        sendScrollMessage(delayTimeInMills);    }    /**     * stop auto scroll     */    public void stopAutoScroll() {        isAutoScroll = false;        handler.removeMessages(SCROLL_WHAT);    }    /**     * set the factor by which the duration of sliding animation will change     */    public void setScrollDurationFactor(double scrollFactor) {        scroller.setScrollDurationFactor(scrollFactor);    }    private void sendScrollMessage(long delayTimeInMills) {        /** remove messages before, keeps one message is running at most **/        handler.removeMessages(SCROLL_WHAT);        handler.sendEmptyMessageDelayed(SCROLL_WHAT, delayTimeInMills);    }    /**     * set ViewPager scroller to change animation duration when sliding     */    private void setViewPagerScroller() {        try {            Field scrollerField = ViewPager.class.getDeclaredField("mScroller");            scrollerField.setAccessible(true);            Field interpolatorField = ViewPager.class.getDeclaredField("sInterpolator");            interpolatorField.setAccessible(true);            scroller = new CustomDurationScroller(getContext(), (Interpolator)interpolatorField.get(null));            scrollerField.set(this, scroller);        } catch (Exception e) {            e.printStackTrace();        }    }    /**     * scroll only once     */    public void scrollOnce() {        PagerAdapter adapter = getAdapter();        int currentItem = getCurrentItem();        int totalCount;        if (adapter == null || (totalCount = adapter.getCount()) <= 1) {            return;        }        int nextItem = (direction == LEFT) ? --currentItem : ++currentItem;        if (nextItem < 0) {            if (isCycle) {                setCurrentItem(totalCount - 1, isBorderAnimation);            }        } else if (nextItem == totalCount) {            if (isCycle) {                setCurrentItem(0, isBorderAnimation);            }        } else {            setCurrentItem(nextItem, true);        }    }    /**     * 
    * if stopScrollWhenTouch is true *
  • if event is down, stop auto scroll.
  • *
  • if event is up, start auto scroll again.
  • *
*/ @Override public boolean onTouchEvent(MotionEvent ev) { if (stopScrollWhenTouch) { if (ev.getAction() == MotionEvent.ACTION_DOWN && isAutoScroll) { isStopByTouch = true; stopAutoScroll(); } else if (ev.getAction() == MotionEvent.ACTION_UP && isStopByTouch) { startAutoScroll(); } } if (slideBorderMode == SLIDE_BORDER_MODE_TO_PARENT || slideBorderMode == SLIDE_BORDER_MODE_CYCLE) { touchX = ev.getX(); if (ev.getAction() == MotionEvent.ACTION_DOWN) { downX = touchX; } int currentItem = getCurrentItem(); PagerAdapter adapter = getAdapter(); int pageCount = adapter == null ? 0 : adapter.getCount(); /** * current index is first one and slide to right or current index is last one and slide to left.
* if slide border mode is to parent, then requestDisallowInterceptTouchEvent false.
* else scroll to last one when current item is first one, scroll to first one when current item is last * one. */ if ((currentItem == 0 && downX <= touchX) || (currentItem == pageCount - 1 && downX >= touchX)) { if (slideBorderMode == SLIDE_BORDER_MODE_TO_PARENT) { getParent().requestDisallowInterceptTouchEvent(false); } else { if (pageCount > 1) { setCurrentItem(pageCount - currentItem - 1, isBorderAnimation); } getParent().requestDisallowInterceptTouchEvent(true); } return super.onTouchEvent(ev); } } getParent().requestDisallowInterceptTouchEvent(true); return super.onTouchEvent(ev); } private class MyHandler extends Handler { @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what) { case SCROLL_WHAT: scrollOnce(); sendScrollMessage(interval); default: break; } } } /** * get auto scroll time in milliseconds, default is {@link #DEFAULT_INTERVAL} * * @return the interval */ public long getInterval() { return interval; } /** * set auto scroll time in milliseconds, default is {@link #DEFAULT_INTERVAL} * * @param interval the interval to set */ public void setInterval(long interval) { this.interval = interval; } /** * get auto scroll direction * * @return {@link #LEFT} or {@link #RIGHT}, default is {@link #RIGHT} */ public int getDirection() { return (direction == LEFT) ? LEFT : RIGHT; } /** * set auto scroll direction * * @param direction {@link #LEFT} or {@link #RIGHT}, default is {@link #RIGHT} */ public void setDirection(int direction) { this.direction = direction; } /** * whether automatic cycle when auto scroll reaching the last or first item, default is true * * @return the isCycle */ public boolean isCycle() { return isCycle; } /** * set whether automatic cycle when auto scroll reaching the last or first item, default is true * * @param isCycle the isCycle to set */ public void setCycle(boolean isCycle) { this.isCycle = isCycle; } /** * whether stop auto scroll when touching, default is true * * @return the stopScrollWhenTouch */ public boolean isStopScrollWhenTouch() { return stopScrollWhenTouch; } /** * set whether stop auto scroll when touching, default is true * * @param stopScrollWhenTouch */ public void setStopScrollWhenTouch(boolean stopScrollWhenTouch) { this.stopScrollWhenTouch = stopScrollWhenTouch; } /** * get how to process when sliding at the last or first item * * @return the slideBorderMode {@link #SLIDE_BORDER_MODE_NONE}, {@link #SLIDE_BORDER_MODE_TO_PARENT}, * {@link #SLIDE_BORDER_MODE_CYCLE}, default is {@link #SLIDE_BORDER_MODE_NONE} */ public int getSlideBorderMode() { return slideBorderMode; } /** * set how to process when sliding at the last or first item * * @param slideBorderMode {@link #SLIDE_BORDER_MODE_NONE}, {@link #SLIDE_BORDER_MODE_TO_PARENT}, * {@link #SLIDE_BORDER_MODE_CYCLE}, default is {@link #SLIDE_BORDER_MODE_NONE} */ public void setSlideBorderMode(int slideBorderMode) { this.slideBorderMode = slideBorderMode; } /** * whether animating when auto scroll at the last or first item, default is true * * @return */ public boolean isBorderAnimation() { return isBorderAnimation; } /** * set whether animating when auto scroll at the last or first item, default is true * * @param isBorderAnimation */ public void setBorderAnimation(boolean isBorderAnimation) { this.isBorderAnimation = isBorderAnimation; }}

自定义ViewPager时用的Scroller

public class CustomDurationScroller extends Scroller {    private double scrollFactor = 1;    public CustomDurationScroller(Context context) {        super(context);    }    public CustomDurationScroller(Context context, Interpolator interpolator) {        super(context, interpolator);    }    /**     * Set the factor by which the duration will change     */    public void setScrollDurationFactor(double scrollFactor) {        this.scrollFactor = scrollFactor;    }    @Override    public void startScroll(int startX, int startY, int dx, int dy, int duration) {        super.startScroll(startX, startY, dx, dy, (int)(duration * scrollFactor));    }}

3.自动滚动核心代码

 用户调用startAutoScroll()后发送一条滚动消息,执行完滚动后重新发送一条滚动消息

 /**     * start auto scroll, first scroll delay time is {@link #getInterval()}     */    public void startAutoScroll() {        isAutoScroll = true;        sendScrollMessage(interval);    } private void sendScrollMessage(long delayTimeInMills) {        /** remove messages before, keeps one message is running at most **/        handler.removeMessages(SCROLL_WHAT);        handler.sendEmptyMessageDelayed(SCROLL_WHAT, delayTimeInMills);    } private class MyHandler extends Handler {        @Override        public void handleMessage(Message msg) {            super.handleMessage(msg);            switch (msg.what) {                case SCROLL_WHAT:                    scrollOnce();                    sendScrollMessage(interval);                default:                    break;            }        }    }

---

4.自动滚动和滑动冲突解决

 /**     * 
    * if stopScrollWhenTouch is true *
  • if event is down, stop auto scroll.
  • *
  • if event is up, start auto scroll again.
  • *
*/ @Override public boolean onTouchEvent(MotionEvent ev) { if (stopScrollWhenTouch) { if (ev.getAction() == MotionEvent.ACTION_DOWN && isAutoScroll) { isStopByTouch = true; stopAutoScroll(); } else if (ev.getAction() == MotionEvent.ACTION_UP && isStopByTouch) { startAutoScroll(); } } ......

5.滑动到边界时的处理

/** * current index is first one and slide to right or current index is last one and slide to left.
* if slide border mode is to parent, then requestDisallowInterceptTouchEvent false.
* else scroll to last one when current item is first one, scroll to first one when current item is last * one. */if ((currentItem == 0 && downX <= touchX) || (currentItem == pageCount - 1 && downX >= touchX)) {if (slideBorderMode == SLIDE_BORDER_MODE_TO_PARENT) {getParent().requestDisallowInterceptTouchEvent(false);} else {if (pageCount > 1) {setCurrentItem(pageCount - currentItem - 1, isBorderAnimation);}getParent().requestDisallowInterceptTouchEvent(true);}return super.onTouchEvent(ev);}

   

至于ViewPager嵌套引起子ViewPager无法触摸问题是通过在子ViewPager的onTouchEvent中添加

Java
1 getParent().requestDisallowInterceptTouchEvent(true);

禁止父控件对touch event做intercept解决的。

 

ViewPager滑动速度的设置是通过反射的方式重新设置ViewPager的Scroller,改变Scroller的startScroll的间隔时间完成的。调用setScrollDurationFactor(double)即可。










更多相关文章

  1. Android(安卓)协调者布局 CoordinatorLayout简单认识
  2. android ViewPager动画的实现原理及效果
  3. android顶部导航条
  4. Android(安卓)Gallery 滑动停止监听方案
  5. 安卓ScrollView嵌套RecyclerView,GridView,ViewPager冲突解决
  6. Android(安卓)向服务器发送get请求乱码问题
  7. Android(安卓)Launcher源码研究(一) 基本结构
  8. Android平台向web应用get、post方式提交信息案例
  9. Android(安卓)ViewPager 实现多个页面切换滑动

随机推荐

  1. php中Date函数和时间戳函数及它们之间格
  2. 集结php常用前端语法
  3. register_shutdown_function函数在php中
  4. 异步执行PHP任务fsockopen的干货
  5. 包含文件include和require在php中的区别(
  6. PHP后端语言与前端JS语法的区别详解
  7. 使用PHPMailer在ThinkPHP5中发送电子邮件
  8. 构造函数在php中的使用方法(附示例)
  9. 使用 PHPStan 强化PHP代码质量
  10. php中函数参数传递的3种方式和区别(附详解