Android多點觸控揭秘

來源:互聯網
上載者:User

本文原創,轉載請註明:http://blog.csdn.net/cloudzfy1/article/details/6582707

Google 暑期大學生部落格分享大賽 - 2011 Android 成長篇

如果您喜歡本文,請您投一下票: http://www.google.com/intl/zh-CN/daxue/blog/vote.html#tab2
謝謝。

最近需要做個Android的項目,需要使用多點觸控的功能,上網找了很久,中文方面的資料相當少,英文方面也不多,經過自己的研究,加上對已知的一些資料的整理,下面為大家介紹一下Android多點觸控程式的編寫。

首先,我們準備好一張圖片:

在Eclipse下建立一個Android工程(和一般Android工程一樣),需要注意的是:Android的多點觸控功能需要運行在Android 2.0版本以上。

完成後,我們需要將原先準備好的圖片放進res/drawable檔案夾下(注意,如果是Android2.2,請放在三個drawable檔案夾下),:

該圖片是為了給該多點觸控的執行個體提供運行環境,實現圖片的放大和縮小。

下面,我們來修改一下main.xml檔案,如下所示:

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:orientation="vertical"    android:layout_width="fill_parent"    android:layout_height="fill_parent"    ><ImageView android:id="@+id/imageView"android:layout_width="fill_parent"android:layout_height="fill_parent"android:src="@drawable/img"android:scaleType="matrix" ></ImageView></LinearLayout>

對於讓一張靜態圖片在Android面板上顯示,我們可以採用下面的一句話:

ImageView imageView = (ImageView)findViewById(R.id.imageView);

 

通過設定Matrix,我們可以獲得對ImageView的一些基本操作。

OK,囉嗦這麼多,下面進入主題:

我們需要實現一個OnTouchListener的方法,來設定ImageView的偵聽屬性,該介面位於android.view.View.OnTouchListener。

實現onTouch(View view, MotionEvent event)的方法,就可以擷取觸屏的感應事件了。

在該事件中,有兩個參數可以用來擷取對觸摸的控制,這兩個參數分別為:MotionEvent.getAction()和MotionEvent.ACTION_MASK,前者用於對單點觸控進行操作,後者用於對多點觸控進行操作,相應地,我們可以通過Android Developers’ Reference看到,對於單點觸控,我們由MotionEvent.getAction()可以得到以下幾種事件:ACTION_DOWN、ACTION_UP,而對於多點觸控,由MotionEvent.ACTION_MASK,我們可以得到:ACTION_POINTER_DOWN、ACTION_POINTER_UP,都是MotionEvent中的常量,可以直接調用。而有些常量則是單點和多點共用的,如:ACTION_MOVE,因此在按下時,我們必須標記單點與多點觸控的區別。

下面我們來介紹一下縮放功能的實現,對於縮放,我們定義有兩種手勢,一種是雙指展開式,一種是單指旋轉式。

首先,雙指展開式。

這是一種比較常規的圖片縮放方式,實現起來也比較方便,我們可以很容易想到,在處理多點觸控事件時,如果沒有別的手勢幹擾,我們只需檢測兩指按下時和移動之後的位置關係即可,如果距離變大,則是放大圖片;反之則是縮小圖片。

主要代碼如下:

 

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);}}

然後,單指旋轉式。

這是一種單指操作中比較流行的方式,然而實現起來並非特別方便。具體說來,我們可以定義順時針轉動為圖片放大,逆時針轉動為圖片縮小。在沒有其他幹擾項的時候,我們可以通過捕獲三次連續移動來得知手勢順時針還是逆時針。如所示,我們把前兩次的位置作一個向量A,後兩次位置作一個向量B,如果向量B比向量A大,則是逆時針;向量B比向量A小則是順時針。當然,我們這裡就要用到反三角函數,同時要注意2pi的角度問題哦~

注意:在處理同為單指操作或者同為多指操作的時候,要考慮不同行為之間的區別。

主要代碼如下:

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;}}

下面是實現的結果:

 初始畫面:

通過滑鼠順時針轉動後的:

通過滑鼠逆時針轉動後的:

下面是代碼的具體解析:

TouchActivity.java

 

package example.MultiTouch;import android.app.Activity;import android.graphics.Matrix;import android.graphics.PointF;import android.os.Bundle;import android.view.MotionEvent;import android.view.View;import android.view.View.OnTouchListener;import android.widget.ImageView;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()        {@Overridepublic 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;}                });    }}

AndroidManifest.xml

 

<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"      package="example.MultiTouch"      android:versionCode="1"      android:versionName="1.0">    <uses-sdk android:minSdkVersion="8" />    <application android:icon="@drawable/icon" android:label="@string/app_name">        <activity android:name=".TouchActivity"                  android:label="@string/app_name">            <intent-filter>                <action android:name="android.intent.action.MAIN" />                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter>        </activity>    </application></manifest>

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.