viewpager 在滑动的过程中是如何触发view身上的事件的,换句话说,viewpager在滑动的过程中到底是滑动的它里面的view,还是滑动的viewpager本身?
一、示例代码:
1、自定义ViewPager:MyViewPager,重新dispatchTouchEvent方法,添加一些事件处理的log信息。
package com.example.viewpagerdemo;
import android.content.Context;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
public class MyViewPager extends ViewPager {
private String TAG = "viewpagertest";
public MyViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.i(TAG , "===MyViewPager MotionEvent.ACTION_DOWN===");
break;
case MotionEvent.ACTION_MOVE:
Log.i(TAG , "===MyViewPager MotionEvent.ACTION_MOVE===");
break;
case MotionEvent.ACTION_UP:
Log.i(TAG , "===MyViewPager MotionEvent.ACTION_UP===");
break;
case MotionEvent.ACTION_CANCEL:
Log.i(TAG , "===MyViewPager MotionEvent.ACTION_CANCEL===");
break;
}
return super.dispatchTouchEvent(ev);
}
}
2、在activity中设置viewpager的数据适配器,给view添加touch事件监听器,添加事件处理的log信息。
package com.example.viewpagerdemo;
import android.app.Activity;
import android.os.Bundle;
import android.support.v4.view.PagerAdapter;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.ImageView;
public class MainActivity extends Activity {
private String TAG = "viewpagertest";
private Integer[] imgList = {R.drawable.first,R.drawable.second,R.drawable.third,R.drawable.four};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
MyViewPager viewPager = (MyViewPager) findViewById(R.id.myviewpager);
viewPager.setAdapter(new MyAdapter());
}
class MyAdapter extends PagerAdapter {
@Override
public int getCount() {
return 4;
}
@Override
public boolean isViewFromObject(View arg0, Object arg1) {
return arg0 == arg1;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
View view = View.inflate(getApplicationContext(), R.layout.view_item, null);
ImageView imageView = (ImageView) view.findViewById(R.id.iv);
imageView.setBackgroundResource(imgList[position]);
view.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.d(TAG , "===view MotionEvent.ACTION_DOWN===");
break;
case MotionEvent.ACTION_MOVE:
Log.d(TAG , "===view MotionEvent.ACTION_MOVE===");
break;
case MotionEvent.ACTION_UP:
Log.d(TAG , "===view MotionEvent.ACTION_UP===");
break;
case MotionEvent.ACTION_CANCEL:
Log.d(TAG , "===view MotionEvent.ACTION_CANCEL===");
break;
}
return true;
}
});
((MyViewPager)container).addView(view);
return view;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
((MyViewPager)container).removeView((View) object);
}
}
}
二、事件分发测试:
1、点击:
logcat:
分析:
内部view的setOnTouchListener的onTouch()方法返回true,ACTION_DOWN、ACTION_UP事件都由内部view消费掉了。
2、滑动(滑一点点,ViewPager未改变):
logcat:
分析:
分析:
内部view的setOnTouchListener的onTouch()方法返回true,ACTION_DOWN、ACTION_MOVE、ACTION_UP事件都由内部view消费掉了。
3、滑动:
logcat:
分析:内部view的ACTION_CANCEL事件被触发,后续事件被外部viewpager接管。
总结:
前提:内部view的setOnTouchListener的onTouch()方法返回true。(表示该View内部消化掉了所有事件)
滑动viewpager去切换不同的item时:
当滑动的距离没有达到临界值(通常viewpager还在当前item),事件会一直作用在内部的view身上,
当滑动的距离(像素点)达到一定阀值(临界值)时(通常viewpager已滑到下一个item),会触发内部view的ACTION_CANCEL事件。后续的ACTION_MOVE、ACTION_UP都被viewpager接管,作用在外面的viewpager身上。
三、案例
图片轮播图:
效果图:
自定义轮播图viewpager代码:
package com.example.zwdzjs.view;
import java.util.List;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.example.logutil.LogUtil;
import com.example.zwdzjs.R;
import com.lidroid.xutils.BitmapUtils;
public class RollViewPager extends ViewPager {
private String TAG = "RollViewPager";
private Context context;
private List<String> titleList;
private List<String> urlImgList;
private TextView top_news_title;
private MyRollViewPagerAdapter adapter;
private BitmapUtils bitmapUtils;
private int currentItem = 0;
private OnViewPagerItemClickListener onItemClickListener;
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
RollViewPager.this.setCurrentItem(currentItem);
startRoll();
}
};
public RollViewPager(Context context, final List<View> dotviewList, OnViewPagerItemClickListener onViewPagerItemClickListener) {
super(context);
this.context = context;
this.onItemClickListener = onViewPagerItemClickListener;
bitmapUtils = new BitmapUtils(context);
this.setOnPageChangeListener(new OnPageChangeListener() {
@Override
public void onPageSelected(int arg0) {
top_news_title.setText(titleList.get(arg0));
for (int i = 0; i < dotviewList.size(); i++) {
if (arg0 == i) {
dotviewList.get(i).setBackgroundResource(R.drawable.dot_focus);
} else {
dotviewList.get(i).setBackgroundResource(R.drawable.dot_normal);
}
}
}
@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
}
@Override
public void onPageScrollStateChanged(int arg0) {
}
});
this.setCurrentItem(currentItem);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
handler.removeCallbacksAndMessages(null);
}
private int downX;
private int downY;
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
// 让当前viewpager的父控件不去拦截touch事件
getParent().requestDisallowInterceptTouchEvent(true);
downX = (int) ev.getX();
downY = (int) ev.getY();
break;
case MotionEvent.ACTION_MOVE:
int moveX = (int) ev.getX();
int moveY = (int) ev.getY();
if (Math.abs(moveX - downX) >= Math.abs(moveY - downY)) {
// 滑动轮播图
getParent().requestDisallowInterceptTouchEvent(true);
} else {
// 刷新listview
getParent().requestDisallowInterceptTouchEvent(false);
}
break;
}
return super.dispatchTouchEvent(ev);
}
public void initTitleLists(TextView top_news_title, List<String> titleList) {
if (null != top_news_title && null != titleList && titleList.size() > 0) {
top_news_title.setText(titleList.get(0));
}
this.titleList = titleList;
this.top_news_title = top_news_title;
}
public void initUrlImgList(List<String> urlImgList) {
this.urlImgList = urlImgList;
LogUtil.d(TAG, "=====urlImgList size:"+urlImgList.size());
}
/**
* 滚动viewpager
*/
public void startRoll() {
if (adapter == null) {
adapter = new MyRollViewPagerAdapter();
this.setAdapter(adapter);
} else {
adapter.notifyDataSetChanged();
}
handler.postDelayed(new Runnable() {
@Override
public void run() {
currentItem = (currentItem + 1)%urlImgList.size();
handler.obtainMessage().sendToTarget();
}
}, 3000);
}
class MyRollViewPagerAdapter extends PagerAdapter {
@Override
public int getCount() {
return urlImgList.size();
}
@Override
public boolean isViewFromObject(View arg0, Object arg1) {
return arg0 == arg1;
}
@Override
public Object instantiateItem(ViewGroup container, final int position) {
View view = View.inflate(context, R.layout.viewpager_item, null);
ImageView imageView = (ImageView) view.findViewById(R.id.image);
bitmapUtils.display(imageView, urlImgList.get(position));
view.setOnTouchListener(new OnTouchListener() {
private int downX;
private int downY;
private long downTime;
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
handler.removeCallbacksAndMessages(null);
downX = (int)event.getX();
downY = (int)event.getY();
downTime = System.currentTimeMillis();
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
if (System.currentTimeMillis() - downTime < 500
&& Math.abs(downX - event.getX()) < 5
&& Math.abs(downY - event.getY()) < 5) {
LogUtil.d(TAG, "=====imageView被点击了, 跳转到对应新闻内容页面");
// 接口回调
if (onItemClickListener != null) {
onItemClickListener.onClick(position);
}
}
startRoll();
break;
case MotionEvent.ACTION_CANCEL:
startRoll();
break;
}
return true;
}
});
((RollViewPager)container).addView(imageView);
return imageView;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
((RollViewPager)container).removeView((View) object);
}
}
/**
* viewpager 的 item 被点击时 回调用的接口
* @author lenovo
*
*/
public interface OnViewPagerItemClickListener {
public void onClick(int i);
}
}
问题:
手指touch到轮播图上时,暂停轮播。手动滑动到下一轮播图后,程序不能自动轮播了
解决方法: