扩展ViewFlow避免和ViewPager滑动冲突,同时支持无限循环,并完美和CircleFlowIndicator结合

简介:

首先,为了避免滑动冲突,我们要继承ViewFlow,重写onInterceptTouchEvent

复制代码
 1 public class MyViewFlow extends ViewFlow {
 2     private ViewPager mPager;
 3 
 4     public MyViewFlow(Context context, AttributeSet attrs) {
 5         super(context, attrs);
 6     }
 7 
 8 
 9     public void setViewPager(ViewPager viewPager) {
10         mPager = viewPager;
11     }
12 
13     @Override
14     public boolean onInterceptTouchEvent(MotionEvent ev) {
15         if (mPager != null)
16             switch (ev.getAction()) {
17                 case MotionEvent.ACTION_DOWN:
18                     mPager.requestDisallowInterceptTouchEvent(true);
19                     break;
20                 case MotionEvent.ACTION_UP:
21                     mPager.requestDisallowInterceptTouchEvent(false);
22                     break;
23                 case MotionEvent.ACTION_CANCEL:
24                     mPager.requestDisallowInterceptTouchEvent(false);
25                     break;
26                 case MotionEvent.ACTION_MOVE:
27                     mPager.requestDisallowInterceptTouchEvent(true);
28                     break;
29             }
30         return super.onInterceptTouchEvent(ev);
31     }
32 }
复制代码

 调用setViewPager指定viewPager后,滑动便不再冲突

 

接下来,我们实现无限循环滚动

复制代码
 1 public class AdapterBanner extends BaseAdapter {
 2 
 3     private LayoutInflater mInflater;
 4     private static final int[] ids = { R.drawable.banner, R.drawable.banner, R.drawable.banner, R.drawable.banner};
 5 
 6     public AdapterBanner(Context context) {
 7         mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
 8     }
 9 
10     @Override
11     public int getCount() {
12         //return ids.length;
13         return Integer.MAX_VALUE;//返回很大的值使得getView中的position不断增大来实现循环
14     }
15 
16     @Override
17     public Object getItem(int position) {
18         return position;
19     }
20 
21     @Override
22     public long getItemId(int position) {
23         return position;
24     }
25 
26     @Override
27     public View getView(int position, View convertView, ViewGroup parent) {
28         if (convertView == null) {
29             convertView = mInflater.inflate(R.layout.item_fr_acmain_nearby_banner, null);
30         }
31         convertView.findViewById(R.id.imgView).setBackgroundResource(ids[position%ids.length]);
32         return convertView;
33     }
34 
35 }
复制代码

关键代码在第13行和31行的红色部分。不过这样实现之后,和CircleFlowIndicator结合使用,会发现程序ANR(无响应),原因是CircleFlowIndicator会调用ViewFlow.getViewCount()来绘制圆点,显然这个数是Integer.MAX_VALUE,圆点数太多了导致ANR,我们需要继续扩展MyViewFlow的getViewCount()。如下。

复制代码
1     private int mCount;
2     public void setCount(int count){
3         mCount=count;
4     }
5     @Override
6     public int getViewsCount() {
7         return mCount;
8     }
复制代码

需要调用MyViewFlow.setCount(int count)指定真实的数目,这样做了之后,发现程序不会ANR了。CircleFlowIndicator绘制的圆点数目也正常。但是会发现,无论怎么滑动,圆点状态都不变化,分析ViewFlow的源码,发现要重写一下onScrollChanged,我们继续扩展MyViewFlow,代码如下。

复制代码
 1     private int mLastIndex;
 2     @Override
 3     public void setAdapter(Adapter adapter, int initialPosition){
 4         super.setAdapter(adapter,initialPosition);
 5         mLastIndex = initialPosition;
 6     }
 7 
 8     @Override
 9     protected void onScrollChanged(int h, int v, int oldh, int oldv) {
10         //super.onScrollChanged(h, v, oldh, oldv);
11         if (mIndicator != null) {
12             /*
13              * The actual horizontal scroll origin does typically not match the
14              * perceived one. Therefore, we need to calculate the perceived
15              * horizontal scroll origin here, since we use a view buffer.
16              */
17             int hPerceived = h + (mCurrentAdapterIndex%mCount - mCurrentBufferIndex)
18                     * getChildWidth();
19 
20             if(mLastIndex%mCount==mCount-1 && mCurrentAdapterIndex>mLastIndex) {
21                 oldh=0;
22                 hPerceived = 0;
23             }
24             if(mLastIndex%mCount==0&&mCurrentAdapterIndex<mLastIndex)
25                 hPerceived=h+(mCount-1-mCurrentBufferIndex)*getChildWidth();
26 
27             LogUtil.e(Config.MYTAG,"mCurrentAdapterIndex="+mCurrentAdapterIndex);
28             LogUtil.e(Config.MYTAG,"mLastIndex="+mLastIndex);
29             LogUtil.e(Config.MYTAG, "hPerceived=" + hPerceived);
30 
31             mIndicator.onScrolled(hPerceived, v, oldh, oldv);
32 
33             mLastIndex=mCurrentAdapterIndex;
34         }
35
复制代码

当然,有几个变量mIndicator,mCurrentAdapterIndex,mCurrentBufferIndex是沿用父类ViewFlow的,如果找不到,需要将父类ViewFlow中这些变量改为public即可(虽然从oop角度,这种做法很脏,但很省事,大半夜码文字很累,我很懒)。

至此,大功告成!

整体MyViewFlow代码如下:

复制代码
package common.control.viewflow;

import android.content.Context;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.Adapter;

import com.xxx.android.main.Config;

import common.util.LogUtil;


public class MyViewFlow extends ViewFlow {
    private ViewPager mPager;

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


    public void setViewPager(ViewPager viewPager) {
        mPager = viewPager;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        if (mPager != null)
            switch (ev.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    mPager.requestDisallowInterceptTouchEvent(true);
                    break;
                case MotionEvent.ACTION_UP:
                    mPager.requestDisallowInterceptTouchEvent(false);
                    break;
                case MotionEvent.ACTION_CANCEL:
                    mPager.requestDisallowInterceptTouchEvent(false);
                    break;
                case MotionEvent.ACTION_MOVE:
                    mPager.requestDisallowInterceptTouchEvent(true);
                    break;
            }
        return super.onInterceptTouchEvent(ev);
    }
    private int mCount;
    public void setCount(int count){
        mCount=count;
    }
    @Override
    public int getViewsCount() {
        return mCount;
    }
    private int mLastIndex;
    @Override
    public void setAdapter(Adapter adapter, int initialPosition){
        super.setAdapter(adapter,initialPosition);
        mLastIndex = initialPosition;
    }

    @Override
    protected void onScrollChanged(int h, int v, int oldh, int oldv) {
        //super.onScrollChanged(h, v, oldh, oldv);
        if (mIndicator != null) {
            /*
             * The actual horizontal scroll origin does typically not match the
             * perceived one. Therefore, we need to calculate the perceived
             * horizontal scroll origin here, since we use a view buffer.
             */
            int hPerceived = h + (mCurrentAdapterIndex%mCount - mCurrentBufferIndex)
                    * getChildWidth();

            if(mLastIndex%mCount==mCount-1 && mCurrentAdapterIndex>mLastIndex) {
                oldh=0;
                hPerceived = 0;
            }
            if(mLastIndex%mCount==0&&mCurrentAdapterIndex<mLastIndex)
                hPerceived=h+(mCount-1-mCurrentBufferIndex)*getChildWidth();

            LogUtil.e(Config.MYTAG,"mCurrentAdapterIndex="+mCurrentAdapterIndex);
            LogUtil.e(Config.MYTAG,"mLastIndex="+mLastIndex);
            LogUtil.e(Config.MYTAG, "hPerceived=" + hPerceived);

            mIndicator.onScrolled(hPerceived, v, oldh, oldv);

            mLastIndex=mCurrentAdapterIndex;
        }
    }
}
复制代码

自动播放就不用讲了,网上很多。同学们如果有收获,记得回赞。


本文转自Kai的世界,道法自然博客园博客,原文链接:http://www.cnblogs.com/kaima/p/3999390.html,如需转载请自行联系原作者。

目录
相关文章
|
3月前
|
Android开发
Android使用ViewPager做无限轮播,人为滑动时停止
Android使用ViewPager做无限轮播,人为滑动时停止
80 2
|
Android开发
两种方法,教你解决 ViewPager 嵌套 ViewPager滑动冲突(一)
两种方法,教你解决 ViewPager 嵌套 ViewPager滑动冲突
|
Android开发 UED 开发者
两种方法,教你解决 ViewPager 嵌套 ViewPager滑动冲突(二)
两种方法,教你解决 ViewPager 嵌套 ViewPager滑动冲突
|
Android开发
Android 中ViewPager嵌套RecyclerView出现滑动冲突的解决方案
Android 中ViewPager嵌套RecyclerView出现滑动冲突的解决方案
1021 0
手把手带你用viewpager实现gallary效果,外加无限循环,自动轮播
手把手带你用viewpager实现gallary效果,外加无限循环,自动轮播 主要功能: ①Gallary样式 ②无限轮播 ③自动轮播和手势操作间冲突解决
|
Android开发
ViewPager源码分析(2):滑动及冲突处理
我的简书同步发布:ViewPager源码分析(2):滑动及冲突处理 转载请注明出处:【huachao1001的专栏:http://blog.csdn.net/huachao1001】 上一篇介绍了ViewPager的onMeasure和onLayout两个方法,这是自定义View最基本的两个函数。但是我们的ViewPager有个需求就是滑动,接下来我们一起去学习ViewPager在滑动方面做了哪些工作,以及ViewPager如何处理与子View之间的滑动冲突。由于ViewPager的子View有Decor View还有普通的子View,而本篇文章讲的主要是普通子View,因此,不再去刻意区
ViewPager源码分析(2):滑动及冲突处理
|
缓存
ViewPager懒加载的实现,理解setUserVisibleHint,而不只是会用就好
Viewpager默认会缓存临近操作的两个页面,也就是至少会缓存一个页面。
206 0
ViewPager懒加载的实现,理解setUserVisibleHint,而不只是会用就好
ViewPager如何区分自动切换和手势滑动切换
ViewPager是一个很常见的组件,不仅支持收拾滑动切换页面,我们还可以通过`viewPager.setCurrentItem(index)`来切换到指定的页面,那么他们如何区分呢? 我们知道ViewPager可以添加`ViewPager.OnPageChangeListener`监听器,可以监听切换的状态。通过观察`ViewPager.OnPageChangeListener#onPageScrollStateChanged(int state)`方法中state的输出,发现了手势切换和自动切换的规律。
|
算法 Android开发
Android嵌套滑动机制分析
Android嵌套滑动机制分析
Android嵌套滑动机制分析