在上一章 中的解决android中HorizontalScrollView的滚动事件与组件的Touch冲突问题 这一篇文章中虽然组件能够在滑动的时候检测到up事件,但是无法滑动,而在这里我们可以用另一种方法来实现,那就是当我们touch的时候,在MotionEvent中有一种情况就是MotionEvent.ACTION_CANCEL,这个事件是指Touch事件的取消通知,这样我们虽然无法捕获up事件但是我们可以通过MotionEvent.ACTION_CANCEL来判断用户之前是否进行了MotionEvent.ACTION_DOWN事件,如果用户MotionEvent.ACTION_DOWN则设置flag =0,当进入CANCEL时,判断一下当前是否flag ==0 ,如果等于0,则这里实现up的功能。
当然这种方法也不是完美的,原因在于用户是想实现组件的touch事件还是实现滚动事件,因为如果用户想滑动的,但是用户却触摸到实现Touch事件的组件,如果用户想实现组件的touch事件,但是却移动了一下组件,这个定界不好解决,
还有一个折中的方法就是触摸点的坐标,这里假设组件是宽大于高,那我们就要用event.getX(),当手的MotionEvent.ACTION_MOVE触摸点与MotionEvent.ACTION_DOWN的间距大于diff(这个用户自己设置),我们就认为它是滑动,这时设置flag=-1,否则我们认为是组件的Touch事件,那就重写onInterceptTouchEvent,内容如下:
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
Log.e("tet", MainActivity.flag+" ");
if (MainActivity.flag == -1) {
return super.onInterceptTouchEvent(ev);
}else{
return false;
}
}
返回false,让组件实现Touch的up事件。
当然我们不可能无限制的去检测距离来判断,因为有时我们我们需要在Down的时候改变组件的背景,当松开手的时候,再次改变组件的背景,所以,我们还要添加一个时间的检测功能,当在timeout(用户自己设置)内并且小于diff,则我们认为是组件的touch事件,否则则认为是滚动事件。综上所述,我们就可以解决滚动和Touch的冲突问题。
Horizon.java内容:
package com.example.test;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.HorizontalScrollView;
public class Horizon extends HorizontalScrollView{
public Horizon(Context context) {
super(context);
}
public Horizon(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
Log.e("tet", MainActivity.flag+" ");
if (MainActivity.flag == 0) {
return false;
}else{
return super.onInterceptTouchEvent(ev);
}
}
}
主类:
package com.example.test;
import android.os.Bundle;
import android.app.Activity;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.widget.Button;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn1 = (Button)findViewById(R.id.btn1);
btn1.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
flag = 0;
Down_t = System.currentTimeMillis();
Down_x = event.getX();
Log.e("test", "down "+event.getX());
break;
case MotionEvent.ACTION_MOVE:
if (Math.abs(event.getX() - Down_x) > diff && (System.currentTimeMillis() - Down_t) <= timeout) {
flag = 1;//认为是滑动
}
Log.e("test", "move "+event.getX());
break;
case MotionEvent.ACTION_UP:
Log.e("test", "up");
flag = -1;
break;
case MotionEvent.ACTION_CANCEL:
if(flag == 0 || flag == 1){
flag = -1;
}
Log.e("test", "cancel");
break;
}
return false;
}
});
btn3 = (Button)findViewById(R.id.btn3);
btn3.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Log.e("tec", "clic");
}
});
}
public Button btn1;
public Button btn3;
public static int flag = -1;
public float Down_x = 0;
public float diff = 2;
public long Down_t = 0;
public long timeout = 100;
}
所以上面我们在Touch上面的Down事件中改变图片的功能,在Move的else里面来实现
case MotionEvent.ACTION_MOVE:
if (Math.abs(event.getX() - Down_x) > diff && (System.currentTimeMillis() - Down_t) <= timeout) {
flag = 1;
}else{
}
当然还需要精细一点的就是Touch事件中的MOVE事件太多,我们可以添加一个标志位,只有在flag ==0的时候才去判断间距和超时,同样改变背景颜色的只有在flag =0的时候,还要设置flag = 2,这样即使move事件也不会进入这两个判断条件,但是相应的Horizon这个类中的判断条件相应的还要添加一个条件,
if (MainActivity.flag == 0 || MainActivity.flag == 2) {
return false;
}else{
return super.onInterceptTouchEvent(ev);
}
同样下面的MOVE代码如下:
case MotionEvent.ACTION_MOVE:
if (flag == 0 && Math.abs(event.getX() - Down_x) > diff && (System.currentTimeMillis() - Down_t) < timeout) {
flag = 1;//认为是滑动
}else if(flag == 0 && Math.abs(event.getX() - Down_x) <= diff && (System.currentTimeMillis() - Down_t) >= timeout){
flag = 2;
}
Log.e("test", "move "+event.getX());
break;