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

扩展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     @Override14     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     @Override11     public int getCount() {12         //return ids.length;13         return Integer.MAX_VALUE;//返回很大的值使得getView中的position不断增大来实现循环14     }15 16     @Override17     public Object getItem(int position) {18         return position;19     }20 21     @Override22     public long getItemId(int position) {23         return position;24     }25 26     @Override27     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     @Override6     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 the14              * perceived one. Therefore, we need to calculate the perceived15              * 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;        }    }}

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

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