Android多点触控MultiTouch浅析

申明:

 

下面实现如何通过应用层支持多点触控操作,对于常规的控件触控操实现onTouchEvent()方法来处理。同时对onTouchEvent方法的参数MotionEvent进行一些了解。

 

正文:

下面会用两个应用示例来初步学习一下Android中的多点触控。

 

示例一(DemoMultiTouch-Canvas):

核心技术介绍

本示例是在SurfaceView中利用Canvas来展示用户的多点触控,不过核心技术还是一个常见的方法:onTouchEvent(MotionEvent event)

MotionEvent有以下几个方法需要大家注意一下,不过了是一些常见的方法,如果你onTouchEvent使用得多的话。

event.getAction() // 获取触控动作比如ACTION_DOWN
event.getPointerCount(); // 获取触控点的数量,比如2则可能是两个手指同时按压屏幕
event.getPointerId(nID); // 对于每个触控的点的细节,我们可以通过一个循环执行getPointerId方法获取索引
event.getX(nID); // 获取第nID个触控点的x位置
event.getY(nID); // 获取第nID个点触控的y位置
event.getPressure(nID); // LCD可以感应出用户的手指压力,当然具体的级别由驱动和物理硬件决定的
event.getDownTime() // 按下开始时间
event.getEventTime() // 事件结束时间
event.getEventTime()-event.getDownTime()); // 总共按下时花费时间

 

代码展示:

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
public class MTView extends SurfaceView implements SurfaceHolder.Callback {
 
     private static final int MAX_TOUCHPOINTS = 10 ;
     private static final String START_TEXT = "请随便触摸屏幕进行测试" ;
     private Paint textPaint = new Paint();
     private Paint touchPaints[] = new Paint[MAX_TOUCHPOINTS];
     private int colors[] = new int [MAX_TOUCHPOINTS];
 
     private int width, height;
     private float scale = 1 .0f;
 
     public MTView(Context context) {
         super (context);
         SurfaceHolder holder = getHolder();
         holder.addCallback( this );
         setFocusable( true ); // 确保我们的View能获得输入焦点
         setFocusableInTouchMode( true ); // 确保能接收到触屏事件
         init();
     }
 
     private void init() {
         // 初始化10个不同颜色的画笔
         textPaint.setColor(Color.WHITE);
         colors[ 0 ] = Color.BLUE;
         colors[ 1 ] = Color.RED;
         colors[ 2 ] = Color.GREEN;
         colors[ 3 ] = Color.YELLOW;
         colors[ 4 ] = Color.CYAN;
         colors[ 5 ] = Color.MAGENTA;
         colors[ 6 ] = Color.DKGRAY;
         colors[ 7 ] = Color.WHITE;
         colors[ 8 ] = Color.LTGRAY;
         colors[ 9 ] = Color.GRAY;
         for ( int i = 0 ; i < MAX_TOUCHPOINTS; i++) {
             touchPaints[i] = new Paint();
             touchPaints[i].setColor(colors[i]);
         }
     }
 
     /**
      * 处理触屏事件
      */
     @Override
     public boolean onTouchEvent(MotionEvent event) {
         // 获得屏幕触点数量
         int pointerCount = event.getPointerCount();
         if (pointerCount > MAX_TOUCHPOINTS) {
             pointerCount = MAX_TOUCHPOINTS;
         }
         
         // 锁定Canvas,开始进行相应的界面处理
         Canvas c = getHolder().lockCanvas();
         if (c != null ) {
             c.drawColor(Color.BLACK);
             if (event.getAction() == MotionEvent.ACTION_UP) {
                 // 当手离开屏幕时,清屏
             } else {
                 // 在每一个触点上绘制一个十字和坐标信息
                 for ( int i = 0 ; i < pointerCount; i++) {
                     int id = event.getPointerId(i);
                     int x = ( int ) event.getX(i);
                     int y = ( int ) event.getY(i);
                     drawCrosshairsAndText(x, y, touchPaints[id], i, id, c);
                 }
                 
                 // 在每一个触点上绘制一个圆
                 for ( int i = 0 ; i < pointerCount; i++) {
                     int id = event.getPointerId(i);
                     int x = ( int ) event.getX(i);
                     int y = ( int ) event.getY(i);
                     drawCircle(x, y, touchPaints[id], c);
                 }
             }
             
             // 画完后,unlock
             getHolder().unlockCanvasAndPost(c);
         }
         return true ;
     }
 
     /**
      * 画十字及坐标信息
      *
      * @param x
      * @param y
      * @param paint
      * @param ptr
      * @param id
      * @param c
      */
     private void drawCrosshairsAndText( int x, int y, Paint paint, int ptr,
             int id, Canvas c) {
         c.drawLine( 0 , y, width, y, paint);
         c.drawLine(x, 0 , x, height, paint);
         int textY = ( int ) (( 15 + 20 * ptr) * scale);
         c.drawText( "x" + ptr + "=" + x, 10 * scale, textY, textPaint);
         c.drawText( "y" + ptr + "=" + y, 70 * scale, textY, textPaint);
         c.drawText( "id" + ptr + "=" + id, width - 55 * scale, textY, textPaint);
     }
 
     /**
      * 画圆
      *
      * @param x
      * @param y
      * @param paint
      * @param c
      */
     private void drawCircle( int x, int y, Paint paint, Canvas c) {
         c.drawCircle(x, y, 40 * scale, paint);
     }
 
     /**
      * 进入程序时背景画成黑色,然后把START_TEXT写到屏幕
      */
     public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
         this .width = width;
         this .height = height;
         if (width > height) {
             this .scale = width / 480f;
         } else {
             this .scale = height / 480f;
         }
         textPaint.setTextSize( 14 * scale);
         Canvas c = getHolder().lockCanvas();
         if (c != null ) {
             c.drawColor(Color.BLACK);
             float tWidth = textPaint.measureText(START_TEXT);
             c.drawText(START_TEXT, width / 2 - tWidth / 2 , height / 2 , textPaint);
             getHolder().unlockCanvasAndPost(c);
         }
     }
 
     public void surfaceCreated(SurfaceHolder holder) {
     }
 
     public void surfaceDestroyed(SurfaceHolder holder) {
     }
}

 

 

使用上也是so easy:

 

?
1
setContentView( new MTView( this ));

 

 

运行效果图:

\


示例二(DemoMultiTouch-ImageView):

通过多点触屏放大或缩小图像 beforeLenght用来保存前一时间两点之间的距离 afterLenght用来保存当前时间两点之间的距离

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public void scaleWithFinger(MotionEvent event) {
             float moveX = event.getX( 1 ) - event.getX( 0 );
             float moveY = event.getY( 1 ) - event.getY( 0 );
 
             switch (event.getAction()) {
             case MotionEvent.ACTION_DOWN:
                 beforeLenght = ( float ) Math.sqrt((moveX * moveX)
                         + (moveY * moveY));
                 break ;
             case MotionEvent.ACTION_MOVE:
                 // 得到两个点之间的长度
                 afterLenght = ( float ) Math.sqrt((moveX * moveX)
                         + (moveY * moveY));
 
                 float gapLenght = afterLenght - beforeLenght;
 
                 if (gapLenght == 0 ) {
                     break ;
                 }
 
                 // 如果当前时间两点距离大于前一时间两点距离,则传0,否则传1
                 if (gapLenght > 0 ) {
                     this .setScale(scale, 0 );
                 } else {
                     this .setScale(scale, 1 );
                 }
 
                 beforeLenght = afterLenght;
                 break ;
             }
         }
     }

 

 

让图片跟随手指触屏的位置移动 beforeX、Y是用来保存前一位置的坐标 afterX、Y是用来保存当前位置的坐标。它们的差值就是ImageView各坐标的增加或减少值。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public void moveWithFinger(MotionEvent event) {
 
             switch (event.getAction()) {
 
             case MotionEvent.ACTION_DOWN:
                 beforeX = event.getX();
                 beforeY = event.getY();
                 break ;
             case MotionEvent.ACTION_MOVE:
                 afterX = event.getX();
                 afterY = event.getY();
 
                 this .setLocation(( int ) (afterX - beforeX),
                         ( int ) (afterY - beforeY));
 
                 beforeX = afterX;
                 beforeY = afterY;
                 break ;
 
             case MotionEvent.ACTION_UP:
                 break ;
             }
         }

 

用来放大缩小ImageView 因为图片是填充ImageView的,所以也就有放大缩小图片的效果 flag为0是放大图片,为1是缩小图片

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
private void setScale( float temp, int flag) {
 
             if (flag == 0 ) {
                 this .setFrame( this .getLeft() - ( int ) (temp * this .getWidth()),
                         this .getTop() - ( int ) (temp * this .getHeight()),
                         this .getRight() + ( int ) (temp * this .getWidth()),
                         this .getBottom() + ( int ) (temp * this .getHeight()));
             } else {
                 this .setFrame( this .getLeft() + ( int ) (temp * this .getWidth()),
                         this .getTop() + ( int ) (temp * this .getHeight()),
                         this .getRight() - ( int ) (temp * this .getWidth()),
                         this .getBottom() - ( int ) (temp * this .getHeight()));
             }
         }

 

 

onTouchEvent事件则如下:

 

?
1
2
3
4
5
6
7
8
9
10
public boolean onTouchEvent(MotionEvent event) {
         if (inView(imageView, event)) {
             if (event.getPointerCount() == 2 ) {
                 imageView.scaleWithFinger(event);
             } else if (event.getPointerCount() == 1 ) {
                 imageView.moveWithFinger(event);
             }
         }
         return true ;
     }

 

源码下载:

https://download.csdn.net/detail/u013761665/8719349

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值