多点触摸和单点触摸的机制一样,都是为触摸事件创建MotionEvent对象,并将这些MotionEvent对象传递给各种方法。
多点触摸的2个重要概念是指针索引和指针ID
指针索引:android把多点触摸时的一个手指抽象成一个“指针”,这个指针有其索引,从0开始。这个索引分配给对应的手指之后,值是会随着手指数量的增减而改变的。如果同时有2根手指在屏幕上,第一根手指指针索引为0,第二根为1,如果第一根手指离开屏幕,第二根的指针索引变为0,因为此刻屏幕上只有1根手指
指针ID:唯一标识一根手指的id,相当于表的主键,这个值和索引不一样,是不会变的。
指针索引和指针ID的关系就像是数据库表中的记录的行号和其主键,删除一条记录,其他记录的行号会发生变化,但是他们的ID是唯一的。
对于多点触摸,MotionEvent中常用到的方法:
getPointerCount():返回MotionEvent中表示了多少手指数
getPointerId(int pointerIndex): 返回指针索引关联的指针ID
getY(int pointerIndex):返回指定指针索引的当前的Y坐标位置
getX(int pointerIndex):返回指定指针索引的当前的X坐标位置
getHistorySize():返回某跟手指触摸事件的历史位置的记录数
getHistoricalX (int pointerIndex, int pos):返回指定指针索引的手指上一次的X坐标位置,只针对移动事件。参数pos是指第几个旧位置,这个值不能超过getHistorySize()返回的值
getHistoricalY (int pointerIndex, int pos):返回指定指针索引的手指上一次的Y坐标位置,只针对移动事件。参数pos是指第几个旧位置,这个值不能超过getHistorySize()返回的值
测试代码:
布局:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity"
android:id="@+id/relativelayout"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world" />
</RelativeLayout>
MainActivity.java:
public class MainActivity extends Activity implements OnTouchListener{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RelativeLayout r = (RelativeLayout)findViewById(R.id.relativelayout);
r.setOnTouchListener(this);
}
@Override
public boolean onTouch(View v, MotionEvent event) {
StringBuilder result = new StringBuilder(500);
//手指的动作
int action = event.getAction();
//几根手指
int points = event.getPointerCount();
result.append("action:" + action).append(",point_count:"+points);
//输出此刻所有手指的状态
for (int i = 0; i < points; i++) {
result.append(",index:").append(i).append(",id:"+ event.getPointerId(i));
result.append(",getX:").append(event.getX(i)).append(",getY:")
.append(event.getY(i));
}
Log.v("test", "---------------------------------------");
Log.v("test", result.toString());
return true;
}
}
现在运行程序,然后放上一根手指在屏幕上,再放一根上去。再依次松开手指,查看日志输出
06-18 23:55:35.612: V/test(10138): ---------------------------------------
06-18 23:55:35.612: V/test(10138): action:0,point_count:1,index:0,id:0,getX:202.0,getY:417.0
06-18 23:55:35.622: V/test(10138): ---------------------------------------
06-18 23:55:35.622: V/test(10138): action:2,point_count:1,index:0,id:0,getX:209.0,getY:418.0
06-18 23:55:35.652: V/test(10138): ---------------------------------------
06-18 23:55:35.652: V/test(10138): action:2,point_count:1,index:0,id:0,getX:212.0,getY:419.0
06-18 23:55:35.662: V/test(10138): ---------------------------------------
06-18 23:55:35.662: V/test(10138): action:2,point_count:1,index:0,id:0,getX:214.0,getY:420.0
06-18 23:55:35.682: V/test(10138): ---------------------------------------
06-18 23:55:35.682: V/test(10138): action:2,point_count:1,index:0,id:0,getX:212.0,getY:419.0
06-18 23:55:35.742: V/test(10138): ---------------------------------------
06-18 23:55:35.742: V/test(10138): action:2,point_count:1,index:0,id:0,getX:215.0,getY:422.0
06-18 23:55:35.772: V/test(10138): ---------------------------------------
06-18 23:55:35.772: V/test(10138): action:2,point_count:1,index:0,id:0,getX:218.0,getY:426.0
06-18 23:55:35.792: V/test(10138): ---------------------------------------
06-18 23:55:35.792: V/test(10138): action:2,point_count:1,index:0,id:0,getX:221.0,getY:428.0
06-18 23:55:35.812: V/test(10138): ---------------------------------------
06-18 23:55:35.812: V/test(10138): action:2,point_count:1,index:0,id:0,getX:223.0,getY:430.0
06-18 23:55:35.832: V/test(10138): ---------------------------------------
06-18 23:55:35.832: V/test(10138): action:2,point_count:1,index:0,id:0,getX:225.0,getY:433.0
06-18 23:55:35.842: V/test(10138): ---------------------------------------
06-18 23:55:35.842: V/test(10138): action:2,point_count:1,index:0,id:0,getX:226.0,getY:435.0
06-18 23:55:35.862: V/test(10138): ---------------------------------------
06-18 23:55:35.862: V/test(10138): action:2,point_count:1,index:0,id:0,getX:227.0,getY:436.0
06-18 23:55:35.882: V/test(10138): ---------------------------------------
06-18 23:55:35.882: V/test(10138): action:2,point_count:1,index:0,id:0,getX:228.0,getY:438.0
06-18 23:55:35.902: V/test(10138): ---------------------------------------
06-18 23:55:35.902: V/test(10138): action:2,point_count:1,index:0,id:0,getX:228.0,getY:439.0
06-18 23:55:35.942: V/test(10138): ---------------------------------------
06-18 23:55:35.942: V/test(10138): action:2,point_count:1,index:0,id:0,getX:227.0,getY:440.0
06-18 23:55:35.972: V/test(10138): ---------------------------------------
06-18 23:55:35.972: V/test(10138): action:2,point_count:1,index:0,id:0,getX:227.0,getY:441.0
06-18 23:55:36.002: V/test(10138): ---------------------------------------
06-18 23:55:36.002: V/test(10138): action:2,point_count:1,index:0,id:0,getX:226.0,getY:441.0
06-18 23:55:36.032: V/test(10138): ---------------------------------------
06-18 23:55:36.032: V/test(10138): action:2,point_count:1,index:0,id:0,getX:227.0,getY:442.0
06-18 23:55:36.072: V/test(10138): ---------------------------------------
06-18 23:55:36.072: V/test(10138): action:2,point_count:1,index:0,id:0,getX:228.0,getY:443.0
06-18 23:55:36.072: V/test(10138): ---------------------------------------
06-18 23:55:36.072: V/test(10138): action:261,point_count:2,index:0,id:0,getX:228.0,getY:443.0,index:1,id:1,getX:388.0,getY:218.0
06-18 23:55:36.092: V/test(10138): ---------------------------------------
06-18 23:55:36.092: V/test(10138): action:2,point_count:2,index:0,id:0,getX:228.0,getY:444.0,index:1,id:1,getX:391.0,getY:222.0
06-18 23:55:36.112: V/test(10138): ---------------------------------------
06-18 23:55:36.112: V/test(10138): action:2,point_count:2,index:0,id:0,getX:228.0,getY:445.0,index:1,id:1,getX:391.0,getY:227.0
06-18 23:55:36.122: V/test(10138): ---------------------------------------
06-18 23:55:36.122: V/test(10138): action:2,point_count:2,index:0,id:0,getX:228.0,getY:447.0,index:1,id:1,getX:397.0,getY:235.0
06-18 23:55:36.142: V/test(10138): ---------------------------------------
06-18 23:55:36.142: V/test(10138): action:2,point_count:2,index:0,id:0,getX:228.0,getY:448.0,index:1,id:1,getX:402.0,getY:245.0
06-18 23:55:36.162: V/test(10138): ---------------------------------------
06-18 23:55:36.162: V/test(10138): action:2,point_count:2,index:0,id:0,getX:227.0,getY:449.0,index:1,id:1,getX:407.0,getY:257.0
06-18 23:55:36.182: V/test(10138): ---------------------------------------
06-18 23:55:36.182: V/test(10138): action:2,point_count:2,index:0,id:0,getX:227.0,getY:450.0,index:1,id:1,getX:414.0,getY:269.0
06-18 23:55:36.202: V/test(10138): ---------------------------------------
06-18 23:55:36.202: V/test(10138): action:2,point_count:2,index:0,id:0,getX:227.0,getY:452.0,index:1,id:1,getX:421.0,getY:279.0
06-18 23:55:36.212: V/test(10138): ---------------------------------------
06-18 23:55:36.212: V/test(10138): action:2,point_count:2,index:0,id:0,getX:227.0,getY:453.0,index:1,id:1,getX:428.0,getY:289.0
06-18 23:55:36.232: V/test(10138): ---------------------------------------
06-18 23:55:36.232: V/test(10138): action:2,point_count:2,index:0,id:0,getX:227.0,getY:455.0,index:1,id:1,getX:434.0,getY:296.0
06-18 23:55:36.252: V/test(10138): ---------------------------------------
06-18 23:55:36.252: V/test(10138): action:2,point_count:2,index:0,id:0,getX:226.0,getY:456.0,index:1,id:1,getX:440.0,getY:302.0
06-18 23:55:36.272: V/test(10138): ---------------------------------------
06-18 23:55:36.272: V/test(10138): action:2,point_count:2,index:0,id:0,getX:226.0,getY:457.0,index:1,id:1,getX:439.0,getY:308.0
06-18 23:55:36.292: V/test(10138): ---------------------------------------
06-18 23:55:36.292: V/test(10138): action:6,point_count:2,index:0,id:0,getX:226.0,getY:457.0,index:1,id:1,getX:439.0,getY:308.0
06-18 23:55:36.292: V/test(10138): ---------------------------------------
06-18 23:55:36.292: V/test(10138): action:1,point_count:1,index:0,id:1,getX:439.0,getY:308.0
红色标注的部分,action261,是在第二根手指放上屏幕的时候,为什么是261呢,看下261转成16进制:0X00000105,这个action由2部分掩码组成,指针索引0x00000100(第2个手指的索引)和操作的常量值ACTION_POINTER_DOWN(0x00000005),当第二根手指触屏时是多点触摸,所以动作是ACTION_POINTER_DOWN而不是ACTION_DOWN。
action:6,此时正是第一根手指离开屏幕,所以action掩码是0x00000000(第一个手指的索引)|0x00000006(ACTION_POINTER_UP),再看下一组输出, action:1,此时屏幕上只有一根手指了,并且离开屏幕,所以action是ACTION_UP。注意到index=0,id=1,和一开始的index=1,id=1不同了,index因为只剩一根手指所以变成了0,这说明了指针索引是不断变化的。
另外,输出历史位置,并没有得到想要的输出,不知道有没有解决过此问题的仁兄,求教
Log.v("test", event.getHistorySize()+"");
for (int j = 0; j < event.getHistorySize(); j++) {
for (int i = 0; i < points; i++) {
result2.append(",index:").append(i).append(",id:"+ event.getPointerId(i));
result2.append(",getHistoricalX:").append(event.getHistoricalX(i, j))
.append(",getHistoricalY:").append(event.getHistoricalY(i, j));
}
}
Log.v("test", "---------------------------------------");
Log.v("test", result2.toString());