1.外部拦截
点击事件斗仙经过父容器的拦截处理,如果父容器需要此事件就拦截,否则就不拦截。外部拦截需要重写父容器的onInterceptTouchEvent方法,在内部做相应的拦截即可。
2.内部拦截
内部拦截是指父容器不拦截任何事件,所有的时间都传递给子元素,如果子元素需要此事件就直接消耗掉,否则交由父容器处理,此方式需要配合requestDisallowInterceptTouchEvent方法才能正常工作。
外部拦截:
我们来实现一个类似于ViewPager中检讨ListView的效果,为了制造滑动冲突,我们写一个类似于ViewPager的控件,名字就叫做HorizontalScrollViewEx
为了实现ViewPager的效果,我们定义了一个类似于水平LinearLayout的东西,只不过他可以水平滑动,初始化时我们在它内部添加若干ListView,这样一来内部的ListView和本身出现了类似于场景1中的冲突。
解决代码如下:
public class MainActivity extends Activity {
private HorizontalScrollViewEx mListContainer;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
// TODO Auto-generated method stub
LayoutInflater inflater = getLayoutInflater();
mListContainer = (HorizontalScrollViewEx) findViewById(R.id.testview);
final int screenWidth = MyUtils.getScreenMetrics(this).x;
final int screenHeight = MyUtils.getScreenMetrics(this).y;
for (int i = 0; i < 3; i++) {
ViewGroup layout = (ViewGroup) inflater.inflate(R.layout.content_layout, mListContainer, false);
layout.getLayoutParams().width = screenWidth;
TextView textView = (TextView) layout.findViewById(R.id.title);
textView.setText("page " + (i + 1));
textView.setBackgroundColor(Color.rgb(255 / (i + 1), 255 / (i + 1), 0));
createList(layout);
mListContainer.addView(layout);
}
}
private void createList(ViewGroup layout) {
ListView listView = (ListView) layout.findViewById(R.id.list);
ArrayList<String> datas = new ArrayList<String>();
for (int i = 0; i < 50; i++) {
datas.add("name " + i);
}
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.content_list_item, R.id.name, datas);
listView.setAdapter(adapter);
}
}
我们在MainActivity中创建了3个ListView加入到自定义的HorizontalScrollViewEx 中,这样HorizontalScrollViewEx 为父容器而ListView为子元素。
采用外部拦截的解决方式:
修改父容器的拦截事件即修改HorizontalScrollViewEx 中的onInterceptTouchEvent方法 修改内容如下:
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
boolean intercepted = false;
int x = (int) event.getX();
int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
intercepted = false;
if (!mScroller.isFinished()) {
mScroller.abortAnimation();
intercepted = true;
}
break;
}
case MotionEvent.ACTION_MOVE: {
int deltaX = x - mLastXIntercept;
int deltaY = y - mLastYIntercept;
if (Math.abs(deltaX) > Math.abs(deltaY)) {
intercepted = true;
} else {
intercepted = false;
}
break;
}
case MotionEvent.ACTION_UP: {
intercepted = false;
break;
}
default:
break;
}
mLastX = x;
mLastY = y;
mLastXIntercept = x;
mLastYIntercept = y;
return intercepted;
}
在滑动过程中当水平距离大时Math.abs(deltaX) > Math.abs(deltaY)
就判断为水平滑动。
Demo源码下载
内部拦截:
首先自定义一个ListView:
public class ListViewEx extends ListView {
private HorizontalScrollViewEx2 mHorizontalScrollViewEx2;
// 分别记录上次滑动的坐标
private int mLastX = 0;
private int mLastY = 0;
public ListViewEx(Context context) {
super(context);
}
public ListViewEx(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// TODO Auto-generated constructor stub
}
public ListViewEx(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
mHorizontalScrollViewEx2.requestDisallowInterceptTouchEvent(true);
break;
}
case MotionEvent.ACTION_MOVE: {
int deltaX = x - mLastX;
int deltaY = y - mLastY;
if (Math.abs(deltaX) > Math.abs(deltaY)) {
mHorizontalScrollViewEx2.requestDisallowInterceptTouchEvent(false);
}
break;
}
case MotionEvent.ACTION_UP: {
break;
}
default:
break;
}
mLastX = x;
mLastY = y;
return super.dispatchTouchEvent(event);
}
public void setParent(HorizontalScrollViewEx2 ex) {
// TODO Auto-generated method stub
mHorizontalScrollViewEx2 = ex;
}
}
然后修改父容器的onInterceptTouchEvent方法
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
int action = event.getAction();
if (action == MotionEvent.ACTION_DOWN) {
mLastX = x;
mLastY = y;
if (!mScroller.isFinished()) {
mScroller.abortAnimation();
return true;
}
return false;
} else {
return true;
}
}
这就是内部拦截解决常见冲突
源码Demo