首页 > 代码库 > 扩展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结合