1 简介
Android多点触控在本质上需要LCD驱动和程序本身设计上支持,目前市面上HTC、Motorola和Samsung等知名厂商只要使用电容屏触控原理的手机均可以支持多点触控Multitouch技术,对于网页缩放、手势操作上有更好的用户体验。 在Android平台上事件均使用了MotionEvent对象方式处理,比如开始触控时会触发ACTION_DOWN,而移动操作时为 ACTION_MOVE,最终放开手指时触发ACTION_UP事件。当然还有用户无规则的操作可能触发ACTION_CANCEL这个动作。
需要注意的是:Android的多点触控功能需要运行在Android 2.0版本以上。
首先Android开发网提醒大家多点触控需要LCD驱动和应用软件两个支持才能实现,所以部分比较老的,比如Android 2.0以前或在北美上市的手机可能无法支持多点触控在固件上,由于Apple专利原因在欧洲和亚太地区的Android 2.0以后的新款机型固件均已经在屏幕驱动中支持,同时模拟器也无法实现多点触控的测试。
2 实现步骤
1)第一种情况是直接重载Activity中的onTouchEvent方法。
对于onTouchEvent方法的参数MotionEvent,我们可以详细处理来实现对多点触控的了解,比如
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()); //总共按下时花费时间
2)第二种情况是实现一个OnTouchListener的方法,来设置View的侦听属性,然后实现onTouch(View view, MotionEvent event)的方法,就可以获取触屏的感应事件了。
在该事件中,有两个参数可以用来获取对触摸的控制,这两个参数分别为:MotionEvent.getAction()和MotionEvent.ACTION_MASK,前者用于对单点触控进行操作,后者用于对多点触控进行操作,对于单点触控,由MotionEvent.getAction()可以得到以下几种事件:ACTION_DOWN、ACTION_UP,而对于多点触控,由MotionEvent.ACTION_MASK,我们可以得到:ACTION_POINTER_DOWN、ACTION_POINTER_UP,都是MotionEvent中的常量,可以直接调用。而有些常量则是单点和多点共用的,如:ACTION_MOVE,因此在按下时,必须标记单点与多点触控的区别。
3)注意:android2.2中onTouchEvent(MotionEvent event) 这里可以用event.getActionMasked()表示用于多点触控检测点。而在1.6和2.1中并没有event.getActionMasked()这个方法,其实他就是把event.getAction()& MotionEvent.ACTION_MASK封装了一下。
3 案例
案例一
public
class MultiTouchActivity extends
Activity {
<span style= "color: #008000;" > /** Called when the activity is first created. */ </span>
<span style= "color: #008000;" > @Override </span>
public
void onCreate(Bundle savedInstanceState) {
super .onCreate(savedInstanceState);
setContentView(R.layout.main);
}
|
<span style= "color: #008000;" > @Override </span>
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();
}
}
|
实测效果如下:
情况一:手指1按下没有出现提示;手指1 抬起 也没有出现提示;这是很显然的,因为这时产生的消息是ACTION_DOWN 和 ACTION_UP。
情况二:手指1按下没有提示;手指2按下出现手指2按下的提示;手指2抬起 出现手指2抬起的提示。
情况三:手指1按下没有提示;手指2 按下 出现提示;这时手指1提起出现手指1提起的提示;手指1按下出现手指1按下的提示;
情况四:大家可以放三个手指去尝试下,看看Android 是怎样产生这些消息的。
根据实验的结果,可以得到一句话:当屏幕上有一个手指时可以完美的产生2点触摸的消息;当屏幕上有2个手指时可以完美的产生3点触摸消息,以此类推……。所谓的完美就是指你能正确的得到到底是那个手指进行了操作。
案例二
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;
}
}
案例三
public class GameView2X extends GameView implements SurfaceHolder.Callback {
private float oldDist;
private PointF midPoint = new PointF();
private boolean isZoom = false;
public GameView2X(Context context, AttributeSet attrs) {
super(context, attrs);
}
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
super.actionDown(event);
break;
case MotionEvent.ACTION_POINTER_UP:
isZoom = false;
break;
/**
* API原文是 A non-primary pointer has gone down.
* 翻译过来就是:非第一个点按下
*/
case MotionEvent.ACTION_POINTER_DOWN:
oldDist = spacing(event);
midPoint(midPoint, event);
isZoom = true;
break;
case MotionEvent.ACTION_MOVE:
if (isZoom) {
float newDist = spacing(event);
/**
* 表示新的距离比两个手指刚触碰的距离大
* ( +10个像素用来延迟一下放大,不然稍微动一点像素,也放大,感觉也太快了。)
*/
if (newDist + 10 > oldDist) {
super.getGameThread().getGameDraw()
.checkXY((int) midPoint.x, (int) midPoint.y);
super.getGameThread().getGameDraw().setIsZoom(true);
}
/**
* 表示新的距离比两个手指刚触碰的距离小
*/
if (newDist + 10 < oldDist) {
super.getGameThread().getGameDraw().setIsZoom(false);
GameDraw.newX = 0;
GameDraw.newY = 0;
}
}
super.actionMove(event);
break;
}
return true;
}
private float spacing(MotionEvent event) {
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return FloatMath.sqrt(x * x + y * y);
}
private void midPoint(PointF point, MotionEvent event) {
float x = event.getX(0) + event.getX(1);
float y = event.getY(0) + event.getY(1);
point.set(x / 2, y / 2);
}
}
案例四(图片的放大和缩小)
public class TouchActivity extends Activity {
private static final int NONE = 0;
private static final int MOVE = 1;
private static final int ZOOM = 2;
private static final int ROTATION = 1;
private int mode = NONE;
private Matrix matrix = new Matrix();
private Matrix savedMatrix = new Matrix();
private PointF start = new PointF();
private PointF mid = new PointF();
private float s = 0;
private float oldDistance;
private int rotate = NONE;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ImageView imageView = (ImageView)findViewById(R.id.imageView);
imageView.setOnTouchListener(new OnTouchListener()
{
@Override
public boolean onTouch(View view, MotionEvent event) {
ImageView imageView = (ImageView)view;
switch (event.getAction()&MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
savedMatrix.set(matrix);
start.set(event.getX(), event.getY());
mode = MOVE;
rotate = NONE;
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
break;
case MotionEvent.ACTION_POINTER_DOWN:
oldDistance = (float)Math.sqrt((event.getX(0)-event.getX(1))*(event.getX(0)-event.getX(1))+(event.getY(0)-event.getY(1))*(event.getY(0)-event.getY(1)));
if (oldDistance > 10f) {
savedMatrix.set(matrix);
mid.set((event.getX(0)+event.getX(1))/2, (event.getY(0)+event.getY(1))/2);
mode = ZOOM;
}
case MotionEvent.ACTION_MOVE:
if (mode == MOVE)
{
if(rotate == NONE) {
savedMatrix.set(matrix);
mid.set(event.getX(), event.getY());
rotate = ROTATION;
}
else {
matrix.set(savedMatrix);
double a = Math.atan((mid.y-start.y)/(mid.x-start.x));
double b = Math.atan((event.getY()-mid.y)/(event.getX()-mid.x));
if ((b - a < Math.PI/2 && b - a > Math.PI / 18)||((b + Math.PI) % Math.PI - a < Math.PI/2 && (b + Math.PI) % Math.PI - a > Math.PI / 18)) {
matrix.postScale((float)0.9, (float)0.9);
}
else if ((a - b < Math.PI / 2 && a - b > Math.PI / 18)||((a + Math.PI) % Math.PI - b < Math.PI/2 && (a + Math.PI) % Math.PI - b > Math.PI / 18)) {
matrix.postScale((float)1.1, (float)1.1);
}
start.set(event.getX(), event.getY());
rotate = NONE;
}
}
else if(mode == ZOOM)
{
float newDistance;
newDistance = (float)Math.sqrt((event.getX(0)-event.getX(1))*(event.getX(0)-event.getX(1))+(event.getY(0)-event.getY(1))*(event.getY(0)-event.getY(1)));
if(newDistance > 10f) {
matrix.set(savedMatrix);
matrix.postScale(newDistance/oldDistance, newDistance/oldDistance, mid.x, mid.y);
oldDistance = newDistance;
savedMatrix.set(matrix);
}
}
break;
}
imageView.setImageMatrix(matrix);
return true;
}
});
}
}
转:http://www.cnblogs.com/devinzhang/archive/2012/02/27/2369942.html
分享到:
相关推荐
总之,Android多点触控技术是提升用户体验的重要手段,理解和熟练掌握相关API和手势检测器的使用,可以让你的Android应用更具交互性和趣味性。通过深入研究"PhotoWallFallsDemo"的代码,开发者可以更好地理解如何将...
【Android多点触控技术实战】在Android应用开发中,多点触控技术是一项重要的交互设计,它使得用户可以通过两个或更多的手指同时操作屏幕,从而实现更丰富的交互体验。在这个场景下,我们专注于如何实现图片的自由...
这个"android多点触控demo,两只手同时拖拽"是针对Android平台的一个示例项目,其目标是实现用户可以通过两只手指同时对屏幕上的元素进行拖动操作。 多点触控的基础是Android系统提供的MotionEvent类,它是处理触摸...
总之,Android多点触控技术为用户提供了丰富的交互体验,开发者可以通过巧妙地利用`MotionEvent`、`ScaleGestureDetector`以及`Matrix`类来实现各种复杂的触摸手势。通过研究提供的源码,你将能够更好地理解和运用...
本教程将详细讲解如何实现一个最简单的Android多点触控图片放大功能,无需复杂的代码,主要利用自定义控件和MotionEvent的相关API。 首先,我们需要创建一个自定义的ImageView类,这个类将继承自Android内置的...
总的来说,"BLE_HID_arduinoBLE多点触控"项目结合了物联网、嵌入式系统、无线通信和多点触控技术,提供了一种创新的交互方式,不仅适用于学习和探索,也对实际应用有着广阔的前景。通过不断的调试和完善,可以实现更...