理论上 Android可以处理 多个手指的触摸

来源:互联网 发布:ftp默认使用的端口 编辑:程序博客网 时间:2024/05/09 10:07
理论上 Android可以处理 多达256 个手指的触摸,大概只有章鱼哥能享受这种技术带来的便利。就编程人员来说,编写多点触摸和单点触摸的方式几乎一模一样。其奥秘在于MotionEvent不仅可以封装单点触摸的消息,也可以封装多点触摸的消息。

在处理单点触摸中,我们用到MotionEvent.ACTION_DOWN、ACTION_UP、ACTION_MOVE,然后用一个Switch来分别进行处理。翻开Android文档,我们就可以清楚的知道他们都是一些常量。
ACTION_DOWN     0x00000000         ACTION_UP      0x00000001        ACTION_MOVE      0x00000002
细心看看文档发现还有一些别的常量:
ACTION_POINTER_1_DOWN     0x00000005            ACTION_POINTER_1_UP      0x00000006
ACTION_POINTER_2_DOWN     0x00000105            ACTION_POINTER_2_UP      0x00000106
ACTION_POINTER_3_DOWN     0x00000205            ACTION_POINTER_3_UP      0x00000206
这些常量正是我们用来处理多点触摸的工具。
  • public class MultiTouchActivity extends Activity {
  • /** Called when the activity is first created. */
  • @Override
  • public void onCreate(Bundle savedInstanceState) {
  • super.onCreate(savedInstanceState);
  • setContentView(R.layout.main);
  • }
  • @Override
  • public boolean onTouchEvent(MotionEvent event){
  • int action = event.getAction();
  • switch(action){
  • case MotionEvent.ACTION_POINTER_1_DOWN:
  • showMessage("第一个手指按下");
  • break;
  • case MotionEvent.ACTION_POINTER_1_UP:
  • showMessage("第一个手指抬起");
  • break;
  • case MotionEvent.ACTION_POINTER_2_DOWN:
  • showMessage("第二个手指按下");
  • break;
  • case MotionEvent.ACTION_POINTER_2_UP:
  • showMessage("第二个手指抬起");
  • break;
  • case MotionEvent.ACTION_POINTER_3_DOWN:
  • showMessage("第三个手指按下");
  • break;
  • case MotionEvent.ACTION_POINTER_3_UP:
  • showMessage("第三个手指抬起");
  • break;
  • }
  • return true;
  • }
  • private void showMessage(String s){
  • Toast toast = Toast.makeText(getApplicationContext(), s, Toast.LENGTH_SHORT);
  • toast.show();
  • }
  • }

复制代码
上面的代码和我们处理单点触摸的方式一模一样。借助这个小小的例子,我们看看Android产生多点消息的机制。
情况一:手指1 按下 没有出现提示; 手指1 抬起 也没有出现提示;
这是很显然的,因为这时产生的消息是ACTION_DOWN 和 ACTION_UP。
情况二:手指1按下 没有提示;
手指2按下 出现手指2按下的提示;手指2抬起 出现手指2抬起的提示。
情况三:手指1 按下 没有提示;
手指2 按下 出现提示; 
这时 手指1 提起 出现手指1提起的提示;手指1按下 出现手指1按下的提示;
情况四:大家可以放三个手指去尝试下,看看Android 是怎样产生这些消息的。
根据我们实验的结果,可以得到一句话:当屏幕上有一个手指时 可以完美的产生2点触摸的消息。 当屏幕上有2个手指时可以完美的产生3点触摸消息,以此类推……。所谓的完美就是指你能正确的得到到底是那个手指进行了操作。
这只是一个小小的深入,我们查看文档时,并没有发现ACTION_POINTER_2_MOVE这样的常量。当第二个手指移动时,我们怎么处理这种事件呢?其实,这样的事件常量都是有规律的单点触摸时DOWN 的最后两位是00,UP是01,MOVE是02.多点触摸时,DOWN是05,UP是06, 你可以猜猜MOVE会不会是07呢?再者,POINTER_1 的34位是00,POINTER_2的34位是01,POINTER_3是02。我们几乎可以肯定的说所谓的ACTION_POINTER_2_MOVE就是0x00000107了。
  • public class Pointer2DrawActivity extends Activity {
  • /** Called when the activity is first created. */
  • ImageView imgView;
  • Bitmap bitmap;
  • Canvas canvas;
  • Paint paint;
  • private static final int ACTION_POINTER_2_MOVE = 0x00000107;
  • @Override
  • public void onCreate(Bundle savedInstanceState) {
  • super.onCreate(savedInstanceState);
  • setContentView(R.layout.main);
  • imgView = (ImageView)findViewById(R.id.imgView);
  • Display currentDisplay = getWindowManager().getDefaultDisplay();
  • float dw = currentDisplay.getWidth();
  • float dh = currentDisplay.getHeight();
  • bitmap = Bitmap.createBitmap((int)dw, (int)dh, Config.ARGB_8888);
  • canvas = new Canvas(bitmap);
  • paint = new Paint();
  • paint.setColor(Color.GREEN);
  • imgView.setImageBitmap(bitmap);
  • }
  • @Override
  • public boolean onTouchEvent(MotionEvent event){
  • int action = event.getAction();
  • float x = 0;
  • float y = 0;
  • if(action == ACTION_POINTER_2_MOVE){
  • x = event.getX();
  • y = event.getY();
  • canvas.drawPoint(x, y, paint);
  • imgView.invalidate();
  • }
  • return true;
  • }
  • }

复制代码
这个神奇的Pointer2Draw想要你的第二个手指绘制一些点。一个手指是什么也绘制不了的……
前面写了一个Pointer2Draw的小程序。这个程序的神奇之处在于,你永远也别想绘制出任何东西。原因是根本没有所谓 的0x00000107。下面看看如何正确的处理多点触摸,光靠event.getAction()吃饭的时代已经终结了
  • int pointerCount = event.getPointerCount();
  • int pointerCount = event.getPointerCount();

复制代码
这个函数具体返回值受到物理设备的限制,我费了很大力气将十个手指放到了我的手机上,得到的结果仍然是8。
(2)得到手指的ID:Android提供了两个掩码方便我们操作ACTION_POINTER_ID_MASK 0x0000ff00,和ACTION_POINTER_ID_SHIFT   0x00000008。
  • if(pointerCount>1){
  • pointerId = (action & MotionEvent.ACTION_POINTER_ID_MASK)>>>
  • MotionEvent.ACTION_POINTER_ID_SHIFT;
  • }
  • if(pointerCount>1){
  • pointerId = (action & MotionEvent.ACTION_POINTER_ID_MASK)>>>
  • MotionEvent.ACTION_POINTER_ID_SHIFT;
  • }

复制代码
(3)利用ID获得坐标信息:
  • float x = event.getX(pointerId);//获得第二个手指的坐标
  • float y = event.getY(pointerId);
  • float x = event.getX(pointerId);//获得第二个手指的坐标
  • float y = event.getY(pointerId);

复制代码
下面终于可以让Pointer2Draw运行起来了。
  • public class Pointer2DrawActivity extends Activity implements OnTouchListener{
  • /** Called when the activity is first created. */
  • ImageView imgView;
  • Bitmap bitmap;
  • Canvas canvas;
  • Paint paint;
  • @Override
  • public void onCreate(Bundle savedInstanceState) {
  • super.onCreate(savedInstanceState);
  • setContentView(R.layout.main);
  • imgView = (ImageView)findViewById(R.id.imgView);
  • Display currentDisplay = getWindowManager().getDefaultDisplay();
  • float dw = currentDisplay.getWidth();
  • float dh = currentDisplay.getHeight();
  • bitmap = Bitmap.createBitmap((int)dw, (int)dh, Config.ARGB_8888);
  • canvas = new Canvas(bitmap);
  • paint = new Paint();
  • paint.setColor(Color.GREEN);
  • paint.setStrokeWidth((float) 10.00);//设置笔刷大小,自己的屏幕太犀利了
  • imgView.setImageBitmap(bitmap);
  • imgView.setOnTouchListener(this);
  • }
  • @Override
  • public boolean onTouch(View v, MotionEvent event) {
  • int pointerCount = event.getPointerCount();
  • int pointerId = 0;
  • int action = (event.getAction()&MotionEvent.ACTION_MASK) % 5;//统一单点和多点
  • switch(action){
  • case MotionEvent.ACTION_DOWN:
  • if(pointerCount>1){
  • pointerId = (event.getAction()&MotionEvent.ACTION_POINTER_ID_MASK)>>>
  • MotionEvent.ACTION_POINTER_ID_SHIFT;
  • }
  • break;
  • case MotionEvent.ACTION_MOVE:
  • if(pointerCount == 2){
  • float x = event.getX(1);
  • float y = event.getY(1);
  • canvas.drawPoint((int)x, (int)y, paint);
  • imgView.invalidate();
  • }
  • break;
  • case MotionEvent.ACTION_UP:
  • break;
  • }
  • return true;
  • }
  • }

复制代码
好了,Pointer2Draw终于按照想要的方式运行了。
在进入手势操作前,先来看看一些处理触摸时遗漏了的要点--VelocityTracker。顾名思义,VelocityTracker就是速度跟踪的意思。我们可以获得触摸点的坐标,根据按下的时间可以简单的计算出速度的大小。但是这样会令我们的代码混乱。Android直接提供了一种方式来方便我们获得触摸的速度。
  • public class VelocityTrackerActivityActivity extends Activity {
  • /** Called when the activity is first created. */
  • TextView textView;
  • private VelocityTracker vTracker = null;
  • @Override
  • public void onCreate(Bundle savedInstanceState) {
  • super.onCreate(savedInstanceState);
  • setContentView(R.layout.main);
  • textView = (TextView)findViewById(R.id.textView);
  • }
  • @Override
  • public boolean onTouchEvent(MotionEvent event){
  • int action = event.getAction();
  • switch(action){
  • case MotionEvent.ACTION_DOWN:
  • if(vTracker == null){
  • vTracker = VelocityTracker.obtain();
  • }else{
  • vTracker.clear();
  • }
  • vTracker.addMovement(event);
  • break;
  • case MotionEvent.ACTION_MOVE:
  • vTracker.addMovement(event);
  • vTracker.computeCurrentVelocity(1000);
  • textView.setText("the x velocity is "+vTracker.getXVelocity());
  • textView.append("the y velocity is "+vTracker.getYVelocity());
  • break;
  • case MotionEvent.ACTION_UP:
  • case MotionEvent.ACTION_CANCEL:
  • vTracker.recycle();
  • break;
  • }
  • event.recycle();
  • return true;
  • }
  • }

复制代码
VelocityTracker不仅可以处理单点的速度,也可以获得多点的速度。这和处理多点触摸的方式是一样的,传入一个ID就可以了。VelocityTracker获得的速度是有正负之分,computerCurrentVelocity()可以设置单位。1000 表示每秒多少像素(pix/second),1代表每微秒多少像素(pix/millisecond)。
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 父母总吵架打架怎么办 老婆老提离婚怎么办 睡眠不好脑子疼怎么办 父母离异孩子结婚怎么办 父母离异后房产怎么办 夫妻离婚后孩子怎么办 离婚小孩的户口怎么办 离婚孩子落户口怎么办 父母离婚孩子出生证怎么办 离婚怎么办孩子的户口 离婚了儿子户口怎么办 性格不合离婚 孩子怎么办 前夫不迁走户口怎么办 我想离婚老婆不同意怎么办 要离婚没身份证怎么办 老婆怀孕想离婚怎么办 我老婆起诉离婚怎么办 父母冷战我该怎么办 经常跟父母亲吵架怎么办 14岁父母离婚怎么办 夫妻为钱吵架怎么办 离婚后担心孩子怎么办 不爱对方有孩子怎么办 爸和大伯吵架怎么办 孩子和家长吵架怎么办 老公吵架摔东西怎么办 楼上吵架摔东西怎么办 宿友没素质的人怎么办 父母人品差自私怎么办 家里穷压力大怎么办 偏执型人格障碍怎么办 遇到低素质保安怎么办 和老婆性格不合怎么办 当心理阴暗时怎么办 孩子胆子小怎么办呢? 父母伤亡的孩子怎么办 小孩上课老是走神怎么办 小孩上课老走神怎么办 小孩上课爱走神怎么办 孩子对学习成绩无所谓怎么办 孩子脾气特别倔强怎么办