Android多点触摸.doc_第1页
Android多点触摸.doc_第2页
Android多点触摸.doc_第3页
Android多点触摸.doc_第4页
Android多点触摸.doc_第5页
已阅读5页,还剩7页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

How to use Multi-touch in Android 2This is the first in a series of articles on developing multi-touch applications with Android 2.x. It is excerpted from Chapter 11 of the book “Hello, Android! (3rd edition)”, available in beta now at The Pragmatic Programmers.Introducing multi-touchMulti-touch is simply an extension of the regular touch-screen user interface, using two or more fingers instead of one. Weve used single-finger gestures before, although we didnt call it that. In Chapter 4 we let the user touch a tile in the Sudoku game in order to change it. Thats called a “tap” gesture. Another gesture is called “drag”. Thats where you hold one finger on the screen and move it around, causing the content under your finger to scroll.Tap, drag, and a few other single-fingered gestures have always been supported in Android. But due to the popularity of the Apple iPhone, early Android users sufferedfrom a kind of gesture envy. The iPhone supported multi-touch, in particular the “pinch zoom” gesture.Three common touch gestures: a) tap, b) drag, and c) pinch zoom. (Image courtesy of GestureW)With pinch zoom, you place two fingers on the screen and squeeze them together to make the item youre viewing smaller, or pull them apart to make it bigger. Before Android 2.0 you had to use a clunky zoom control with icons that you pressed to zoom in and out (for example the setBuiltInZoomControls() in the MyMap example). But thanks to its new multi-touch support, you can now pinch to zoom on Android too! As long as the application supports it, of course.Note: If you try to run the example in this chapter on Android 1.5 or 1.6, it will crash because those versions do not support multi-touch. Well learn how to work around that in chapter 13, “Write Once, Test Everywhere”.Warning: Multi-bugs aheadMulti-touch, as implemented on current Android phones is extremely buggy. In fact its so buggy that it borders on the unusable. The API routinely reports invalid or impossible data points, especially during the transition from one finger to two fingers on the screen and vice-versa.On the developer forums you can find complaints of fingers getting swapped, x and y axes flipping, and multiple fingers sometimes being treated as one. With a lot of trial and error, I was able to get the example in this chapter working because the gesture it implements is so simple. Until Google acknowledges and fixes the problems, thatmay be about all you can do. Luckily, pinch zoom seems to be the only multi-touch gesture most people want.The Touch exampleTo demonstrate multi-touch, were going to build a simple image viewer application that lets you zoom in and scroll around an image. Heres a screenshot of the finished product:The Touch example implements a simple image viewer with drag and pinch zoom.Building the Touch exampleTo demonstrate multi-touch, were going to build a simple image viewer application that lets you zoom in and scroll around an image. See Part 1 for a screenshot of the finished product.Begin by creating a new “Hello, Android” project with the following parameters in the New Android Project dialog box:Project name: TouchBuild Target: Android 2.1Application name: TouchPackage name: org.example.touchCreate Activity: TouchThis will create Touch.java to contain your main activity. Lets edit it to show a sample image, put in a touch listener, and add a few imports well need later:From Touchv1/src/org/example/touch/Touch.java:package org.example.touch;import android.app.Activity;import android.graphics.Matrix;import android.graphics.PointF;import android.os.Bundle;import android.util.FloatMath;import android.util.Log;import android.view.MotionEvent;import android.view.View;import android.view.View.OnTouchListener;import android.widget.ImageView;public class Touch extends Activity implements OnTouchListener private static final String TAG = Touch ; Override public void onCreate(Bundle savedInstanceState) super. onCreate(savedInstanceState); setContentView(R.layout.main); ImageView view = (ImageView) findViewById(R.id.imageView); view.setOnTouchListener(this); Override public boolean onTouch(View v, MotionEvent event) / Handle touch events here. Well fill out that onTouch( ) method in a moment. First we need to definethe layout for our activity:From Touchv1/res/layout/main.xml: The entire interface is a big ImageView control that covers the whole screen. The android:src=”drawable/butterfly” value refers to the butterfly image used in the example. You can use any JPG or PNG format image you like, just put it in the res/drawables-nodpi directory. The android:scaleType=”matrix” attribute indicates were going to use a matrix to control the position and scale of the image. More on that later. The AndroidManifest.xml file is untouched except for the addition of the android:theme= attribute:From Touchv1/AndroidManifest.xml: android:style/Theme.NoTitleBar.Fullscreen, as the name suggests, tells Android to use the entire screen with no title bar or status bar at the top. You can run the application now and it will simply display the picture.Understanding touch eventsWhenever I first learn a new API, I like to first put in some code to dump everything out so I can get a feel for what the methods do and in what order events happen. So lets start with that. First add a call to the dumpEvent() method inside onTouch():From Touchv1/src/org/example/touch/Touch.java:Overridepublic boolean onTouch(View v, MotionEvent event) / Dump touch event to log dumpEvent(event); return true; / indicate event was handledNote that we need to return true to indicate to Android that the event has been handled. Next, define the dumpEvent() method. The only parameter is the event that we want to dump.From Touchv1/src/org/example/touch/Touch.java:/* Show an event in the LogCat view, for debugging */private void dumpEvent(MotionEvent event) String names = DOWN , UP , MOVE , CANCEL , OUTSIDE , POINTER_DOWN , POINTER_UP , 7? , 8? , 9? ; StringBuilder sb = new StringBuilder(); int action = event.getAction(); int actionCode = action & MotionEvent.ACTION_MASK; sb.append(event ACTION_ ).append(namesactionCode); if (actionCode = MotionEvent.ACTION_POINTER_DOWN | actionCode = MotionEvent.ACTION_POINTER_UP) sb.append(pid ).append( action MotionEvent.ACTION_POINTER_ID_SHIFT); sb.append() ); sb.append( ); for (int i = 0; i event.getPointerCount(); i+) sb.append(# ).append(i); sb.append(pid ).append(event.getPointerId(i); sb.append()= ).append(int) event.getX(i); sb.append(, ).append(int) event.getY(i); if (i + 1 ) to separate them.Then we call the getPointerCount( ) method to see how many finger positions are included. getX( ) and getY() return the X and Y coordinates, respectively. The fingers can appear in any order, so we have to call the getPointerId() to find out which fingers were really talking about.That covers the raw mouse event data. The trick, as you might imagine, is in interpreting and acting on that data.Setting up for Image TransformationIn order to move and zoom the image well use a neat little feature on the ImageView class called matrix transformation. Using a matrix we can represent any kind of translation, rotation, or skew that we want to do to the image. We already turned it on by specifying android:scaleType=”matrix” in the res/layout/main.xml file. In the Touch class, we need to declare two matrices as fields (one for the current value and one for the original value before the transformation). Well use them in the onTouch( ) method to transform the image. We also need a mode variable to tell whether were in the middle of a drag or zoom gesture:From Touchv1/src/org/example/touch/Touch.java:public class Touch extends Activity implements OnTouchListener / These matrices will be used to move and zoom image Matrix matrix = new Matrix(); Matrix savedMatrix = new Matrix(); / We can be in one of these 3 states static final int NONE = 0; static final int DRAG = 1; static final int ZOOM = 2; int mode = NONE; Override public boolean onTouch(View v, MotionEvent event) ImageView view = (ImageView) v; / Dump touch event to log dumpEvent(event); / Handle touch events here. switch (event.getAction() & MotionEvent.ACTION_MASK) / Perform the transformation view.setImageMatrix(matrix); return true; / indicate event was handled The matrix variable will be calculated inside the switch statement when we implement the gestures.Implementing the Drag GestureA drag gesture starts when the first finger is pressed to the screen (ACTION_DOWN) and ends when it is removed (ACTION_UP or ACTION_POINTER_UP).From: Touchv1/src/org/example/touch/Touch.java:switch (event.getAction() & MotionEvent.ACTION_MASK) case MotionEvent.ACTION_DOWN: savedMatrix.set(matrix); start.set(event.getX(), event.getY(); Log.d(TAG, mode=DRAG ); mode = DRAG; break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_POINTER_UP: mode = NONE; Log.d(TAG, mode=NONE ); break; case MotionEvent.ACTION_MOVE: if (mode = DRAG) matrix.set(savedMatrix); matrix.postTranslate(event.getX() - start.x, event.getY() - start.y); break;When the gesture starts we remember the current value of the transformation matrix and the starting position of the pointer. Every time the finger moves, we start the transformation matrix over at its original value and call the postTranslate( ) method to add a translation vector, the difference between the current and starting positions.If you run the program now you should be able to drag the image around the screen using your finger. Neat, huh?Joe Asks: Why not use the built-in gesture library?The android.gesture package provides a way to create, recognize, load, and save gestures. Unfortunately it is not very useful in practice. Among other problems, it doesnt come with a standard collection of built-in gestures (like tap and drag) and it doesnt support multi-touch gestures such as pinch zoom. Perhaps a future version of Android will include a better gesture library so the code in this chapter could be simplified.Implementing the Pinch Zoom GestureThe pinch zoom gesture is similar to the drag gesture, except it starts when the second finger is pressed to the screen (ACTION_POINTER_DOWN).From Touchv1/src/org/example/touch/Touch.java:case MotionEvent.ACTION_POINTER_DOWN: oldDist = spacing(event); Log.d(TAG, oldDist= + oldDist); if (oldDist 10f) savedMatrix.set(matrix); midPoint(mid, event); mode = ZOOM; Log.d(TAG, mode=ZOOM ); break;case MotionEvent.ACTION_MOVE: if (mode = DRAG) / . else if (mode = ZOOM) float newDist = spacing(event); Log.d(TAG, newDist= + newDist); if (newDist 10f) matrix.set(savedMatrix); float scale = newDist / oldDist; matrix.postScale(scale, scale, mid.x, mid.y); break;When we get the down event for the second finger, we calculate and remember the distance between the two fingers. In my testing, Android would sometimes tell me (incorrectly) that there were two fingers pressed down in almost exactly the same position. So I added an check to ignore the event if the distance is smaller than some arbitrary number of pixels. If its bigger than that, we remember the current transformation matrix, calculate the midpoint of the two fingers, and start the zoom.When a move event arrives while were in zoom mode, we calculate the distance between the fingers again. If its too small, the event is ignored, otherwise we restore the transformation matrix and scale the image around the midpoint.The scale is simply the ratio of the new distance divided by the old distance. If the new distance is bigger (that is, the fingers have gotten further apart), then the scale will be greater than 1, making the image bigger. If its smaller (fingers closer together), then the scale will be less than one, making the image smaller. And of course if everything is the same, the scale is equal to 1 and the image is not changed.Now lets define the spacing( ) and midPoint( ) methods.Distance Between Two PointsTo find out how far apart two fingers are, we first construct a vector (x, y) which is the difference between the two points. Then we use the formula for Euclidean distance to calculate the spacing:From Touchv1/src/org/example/touch/Touch.java: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);The order of the points doesnt matter because any negative signs will be lost when we square them. Note that all math is done using Javas float type. While some Android devices may not have floating point hardware, were not doing this often enough to worry about its performance.Midpoint of Two PointsCalculating a point in the middle of two points is even easier:From Touchv1/src/org/example/touch/Touc

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论