文章转载只能用于非商业性质,且不能带有虚拟货币、积分、注册等附加条件。转载须注明出处http://blog.csdn.net/flowingflying/以及作者@恺风Wei。
MotionEvent对象用于告诉APP用户正在如何使用触摸屏幕。我们可以为view设置触摸回调函数,而view本身也带有触摸回调函数。
为view设置触摸回调函数onTouch()
public class MainActivity extends Activity implements OnTouchListener{
@Override
protected void onCreate(Bundle savedInstanceState) {
……
RelativeLayout layout1 = (RelativeLayout)findViewById(R.id.layout1);
layout1.setOnTouchListener(this);
Button trueButton1 = (Button)findViewById(R.id.trueButton1);
trueButton1.setOnTouchListener(this);
}
@Override //onTouchListener的回调函数onTouch()
public boolean onTouch(View v, MotionEvent event) {
String tag = v.getTag().toString(); //在layout xml中设置android:tag属性,可通过getTag()获取
Log.i(tag,"Got view " + v.getTag().toString() + " in touch");
Log.i(tag,MainActivity.describeEvent(v, event));
return super.onTouchEvent(event);
}
}
自定义view,重写触摸回调函数onTouchEvent()
public class MyButton extends Button{
protected boolean myValue = false;
public BooleanButton(Context context, AttributeSet as){
super(context,as);
}
@Override //对TextView的onTouchEvent()重写
public boolean onTouchEvent(MotionEvent event) {
String tag = this.getTag().toString();
Log.d(tag,MainActivity.describeEvent(this, event));
Log.d(tag,"Now return " + myValue);
return myValue;
}
}
我们可以在layout xml中使用自定义的MyButton,方式如下:
<cn.wei.flowingflying.testtouchscreen.MyButton android:id="@+id/trueButton1"
android:text="Return true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:tag="trueButtonTop" />
MotionEvent可获取的信息
当用户触摸屏幕是,会生成一个MotionEvent对象,含有触摸的信息,应用可以获得这个对象,例如自定义控件中的onTouchEvent()。MotionEvent可以获得很多信息,包括动作类型,如ACTION_DOWN等,触摸的位置,触摸相应的时间,触摸的压力,触摸的大小。前面的小例子中通过静态函数MainActivity.describeEvent(v, event)来显示详细信息,下面是相关代码:
protected static String describeEvent(View view, MotionEvent event) {
String result = "Action: " + getActionName(event.getAction()) + "\n"
+ "Location: " + event.getX() + "," + event.getY() + "\n"; // X,Y是距离view左上角的值
if(event.getX() < 0 || event.getX() > view.getWidth() || event.getY() < 0 || event.getY() > view.getHeight()){
result += ">>> Touch has left the view <<<\n" ;
}
/*【1】getEdgeFlags()获取是否触摸到触屏的边框,但是这个可能永远返回0,例如模拟器和某些手机。在编程中,我们不能依赖这个值,可以自行通过位置计算,通过setEdgeFlage()来设定flags。
*【2】压力和size的范围是0-1,每款设备的检测值有差异,每个绝对值并没有具体的衡量,很难说0.8以上的就是压力大,某款设备可能检测值不会有0.8以上,所有这些数值最好是自己和自己进行比较,获知轻重的变化。在某款手机上,size的值一直为0。*/
result += "Edge Flag: " + event.getEdgeFlags() + "\n"
+ "Pressure : " + event.getPressure() + "\n"
+ "Size : " + event.getSize() + "\n"
+ "Down time :" + event.getDownTime() + "ms\n"
+ "Event time :" + event.getEventTime() + "ms\n"
+ "Eclapsed: " + (event.getEventTime() - event.getDownTime()) + "ms\n";
return result;
}
private static String getActionName(int code){
if(code == MotionEvent.ACTION_DOWN)
return "ACTION_DOWN";
if(code == MotionEvent.ACTION_MOVE)
return "ACTION_MOVE";
……
return ""+code;
}
当手指在某个view中按下,移动,离开,将会依次触发ACTION_DOWN,ACTION_MOVE(0~N个)和ACTION_UP。从DOWN开始,到UP结束,这是一组动作,event.getDownTime()给出的时间是一样的,我们可以通过当前时间event.getEventTime()进行比对,获得动作的持续时间。
除了这三个常见动作事件外,还有ACTION_CANCEL和ACTION_OUTSIDE。
触发的逻辑
用户的一个动作实际是可以分解为若干小动作处理,这一系列动作,从Down开始,在MotionEvent中具有getDownTime(),一般以Up结束。每个事件发生时,可能会有若干个回调函数,这些回调函数是有缺省的顺序,如果回调函数返回false,将触发事件传递到下一个回调函数进行处理,如果回调函数返回true,说明已经全部处理完,不在继续向下传递。这里比较特别的是,如果是最后一个回调函数,如果返回false,则下一个动作不会触发,因此,如果我们明确已经全部处理完,则返回true,否则返回super处理方法的值。
例子说明
以我们之前的代码为例,有一个自定义的button在RelativeLayout上,通过setTouchListener()为这个view都设置了触摸监听器,这个自定义的button,重写了onTouchEvent()。用户按button,触发的顺序如下:
通过setTouchListener()注册的监听器优先于view的onTouchEvent()。如果view在某个view group中,view的触摸触发优先于view group的触摸触发。
如果传递到RelativeLayout的onTouch(),我们看到Event的Y坐标有变化,因为Layout的左上角和Button的左上角位置不同。
如果我们在手指Button出按下,然后滑出Button,然后离开屏幕,这属于一个动作。我们会看到ACTION_DOWN,然后很多ACTION_MOVE,以及最后的ACTION_UP。在这个连续动作中,即使我们的手指已经滑出Button,我们仍可以在Button.onTouch()和Button.onTouchEvent()收到MotionEvent。通过检查具体的X、Y值,可判断是否离开view。无论手指滑到哪里,ACTION_DOWN顺序触发的各回调方法,是接下来这动作组的其他动作触发的顺序。例如我们有两个RelativeLayout,手指从其中要给滑到另一个,因为一开始ACTION_DOWN是在第一个RelativeLayout,所以只会触发到第一个RelativeLayout的回调函数,不会触发到第二个RelativeLayout的触屏回调函数。
一般而言,如果自定义view,我们返回super.onTouchEvent()即可。例如自定义Button,实际上Button接收到DOWN的时候,会改变Button的颜色,而UP的时候,再次变回来,因此需要提供Button缺省的处理。如果,我们确定不将其继续往下传递,可以在return true;之前增加super.onTouchEvent()的处理。如果我们在Button onTouch()就返回true,我们是不会看到Button的颜色有变化,当然我们可以添加view.onTouchEvent(event)来处理,或直接return view.onTouchEvent(event)。
安装会从AndroidManifest中获知信息,如果应用必须要求支持触摸,我们以加上说明。一些运行Android的机顶盒以TV作为屏幕,而TV是不支持触摸屏。
<uses-configuration android:reqTouchScreen="finger" />
android:onClick和触屏回调函数的关系
我们可以在layout.xml文件中对Button控件加入android:onClick=“doClick”,来跟踪按Button的情况。doClick()将在Button的ACTION_UP事件后触发,但是前提是:1、能收到ACTION_UP事件,而且范围在Button内(不滑出);2、能执行button.onTouchEvent(),如果我们重写该方法,要确保执行super.onTouchEvent();
相关小例子代码:Pro Android学习:touch screen小例子