출처 : http://miksnug.pe.kr/24


Android 에서 Multi Touch 를 구현한 Code 입니다.
허접하지만 튜닝하면 좀 더 나아지지 않을까 생각합니다.


+ MainActivity.java
  1. package kr.pe.miksnug;  
  2.   
  3. import java.util.ArrayList;  
  4.   
  5. import android.app.Activity;  
  6. import android.content.Context;  
  7. import android.graphics.Canvas;  
  8. import android.graphics.Color;  
  9. import android.graphics.Paint;  
  10. import android.os.Bundle;  
  11. import android.os.Vibrator;  
  12. import android.view.MotionEvent;  
  13. import android.view.View;  
  14. import android.widget.FrameLayout;  
  15. import android.widget.TextView;  
  16.   
  17. /** 
  18.  * 안드로이드 멀티터치 입니다.<br/> 
  19.  * <br/> 
  20.  * 프로젝트 실행 Main Activity 클래스 <br/> 
  21.  * Android 2.0 이상 지원 <br/> 
  22.  * <br/> 
  23.  * 1. 멀티터치 감지 (구현상 무한대)<br/> 
  24.  * 2. 터치점에 원형 표시<br/> 
  25.  * 3. 누르는 힘에 따라 색깔 및 크기 변경<br/> 
  26.  * 4. 누르는 힘에 따라 진동 변경<br/> 
  27.  * <br/> 
  28.  *  
  29.  * @author yeongeon 
  30.  *  
  31.  */  
  32. public class MainActivity extends Activity {  
  33.   
  34.     /** 
  35.      * 메인 레이아웃 인스턴스 
  36.      */  
  37.     private FrameLayout m_mainLayout = null;  
  38.   
  39.     /** 
  40.      * 디버그 텍스트 출력용 뷰 
  41.      */  
  42.     TextView m_tvDebugText = null;  
  43.     TextView m_tvDebugText2 = null;  
  44.   
  45.       
  46.     /** 
  47.      * 입력된 이벤트 수 
  48.      */  
  49.     private int m_eventCnt = 0;  
  50.   
  51.     /** 
  52.      * 원 도형 View 클래스 
  53.      *  
  54.      * @author yeongeon 
  55.      */  
  56.     class Ball extends View {  
  57.   
  58.         /** 
  59.          * X 좌표 
  60.          */  
  61.         public float m_x;  
  62.   
  63.         /** 
  64.          * Y 좌표 
  65.          */  
  66.         public float m_y;  
  67.   
  68.         /** 
  69.          * 반지름 
  70.          */  
  71.         private int m_r;  
  72.   
  73.         /** 
  74.          * 페인트 인스턴스 
  75.          */  
  76.         private Paint m_paint = new Paint(Paint.LINEAR_TEXT_FLAG);  
  77.   
  78.         /** 
  79.          * 원 도형 생성자 
  80.          *  
  81.          * @param context 
  82.          * @param x 
  83.          * @param y 
  84.          * @param r 
  85.          * @param color 
  86.          */  
  87.         public Ball(Context context, float x, float y, int r, int color) {  
  88.             super(context);  
  89.             m_paint.setColor(color);  
  90.             this.m_x = x;  
  91.             this.m_y = y;  
  92.             this.m_r = r;  
  93.         }  
  94.   
  95.         /** 
  96.          * 도형 그리는 메소드 
  97.          *  
  98.          * @see android.view.View#onDraw(android.graphics.Canvas) 
  99.          */  
  100.         @Override  
  101.         protected void onDraw(Canvas canvas) {  
  102.             canvas.drawCircle(m_x, m_y, m_r, m_paint);  
  103.             super.onDraw(canvas);  
  104.         }  
  105.   
  106.     }  
  107.       
  108.   
  109.     /** 
  110.      * MyText View 클래스 
  111.      *  
  112.      * @author yeongeon 
  113.      */  
  114.     class FloatingText extends View {  
  115.   
  116.         /** 
  117.          * X 좌표 
  118.          */  
  119.         public float m_x;  
  120.   
  121.         /** 
  122.          * Y 좌표 
  123.          */  
  124.         public float m_y;  
  125.   
  126.         /** 
  127.          * 반지름 
  128.          */  
  129.         private String m_t;  
  130.   
  131.         /** 
  132.          * 페인트 인스턴스 
  133.          */  
  134.         private Paint m_paint = new Paint(Paint.LINEAR_TEXT_FLAG);  
  135.   
  136.         /** 
  137.          * 원 도형 생성자 
  138.          *  
  139.          * @param context 
  140.          * @param x 
  141.          * @param y 
  142.          * @param r 
  143.          * @param color 
  144.          */  
  145.         public FloatingText(Context context, float x, float y, String t, int color) {  
  146.             super(context);  
  147.             m_paint.setColor(color);  
  148.             this.m_x = x;  
  149.             this.m_y = y;  
  150.             this.m_t = t;  
  151.         }  
  152.   
  153.         /** 
  154.          * 도형 그리는 메소드 
  155.          *  
  156.          * @see android.view.View#onDraw(android.graphics.Canvas) 
  157.          */  
  158.         @Override  
  159.         protected void onDraw(Canvas canvas) {  
  160.             canvas.drawText(m_t, m_x, m_y, m_paint);  
  161.             super.onDraw(canvas);  
  162.         }  
  163.   
  164.     }  
  165.   
  166.     /** 
  167.      * 터치 이벤트 개별 노드 클래스 
  168.      *  
  169.      * @author yeongeon 
  170.      */  
  171.     class EventNode {  
  172.         /** 
  173.          * 포인터 아이디 
  174.          */  
  175.         private int m_pointerId = -1;  
  176.   
  177.         /** 
  178.          * 포인터 인덱스 
  179.          */  
  180.         private int m_pointerIndex = -1;  
  181.   
  182.         /** 
  183.          * x 좌표 값 
  184.          */  
  185.         private float m_x = -1;  
  186.   
  187.         /** 
  188.          * y 좌표 값 
  189.          */  
  190.         private float m_y = -1;  
  191.   
  192.         /** 
  193.          * 압력 값 
  194.          */  
  195.         private float m_pressure = -1;  
  196.   
  197.         /** 
  198.          * 도형 인스턴스 
  199.          */  
  200.         private Ball m_ball = null;  
  201.   
  202.         /** 
  203.          * Paint 색 
  204.          */  
  205.         private int m_color = Color.YELLOW;  
  206.           
  207.         /** 
  208.          * 진동 시간 간격 
  209.          */  
  210.         int m_vibrationInterval = 2;  
  211.           
  212.         /** 
  213.          * 반지름 
  214.          */  
  215.         int m_radius = 50;  
  216.           
  217.         /** 
  218.          * 떠다니는 문자 인스턴스 
  219.          */  
  220.         FloatingText m_floatingText = null;  
  221.           
  222.           
  223.         /** 
  224.          * 생성자 입니다. 
  225.          *  
  226.          * @param event 
  227.          * @param idx 
  228.          */  
  229.         public EventNode(MotionEvent event, int idx) {  
  230.             this.m_pointerId = event.getPointerId(idx);  
  231.             this.m_pointerIndex = event.findPointerIndex(this.m_pointerId);  
  232.             this.m_x = event.getX(this.m_pointerIndex);  
  233.             this.m_y = event.getY(this.m_pointerIndex);  
  234.             this.setPressure(event.getPressure(this.m_pointerIndex) );  
  235.             if (this.getPressure() >= 0.1 && this.getPressure() < 0.18) {  
  236.                 this.m_color = Color.GREEN;  
  237.                 this.m_vibrationInterval = 3;  
  238.                 this.m_radius = 60;  
  239.             } else if (this.getPressure() > 0.25) {  
  240.                 this.m_color = Color.RED;  
  241.                 this.m_vibrationInterval = 6;  
  242.                 this.m_radius = 100;  
  243.             } else if (this.getPressure() >= 0.18 && this.getPressure() < 0.25) {  
  244.                 this.m_color = Color.BLUE;  
  245.                 this.m_vibrationInterval = 4;  
  246.                 this.m_radius = 70;  
  247.             } else {  
  248.                 this.m_color = Color.YELLOW;  
  249.                 this.m_vibrationInterval = 2;  
  250.                 this.m_radius = 50;  
  251.             }  
  252.             this.m_ball = new Ball(getApplicationContext(), this.getX(), this  
  253.                     .getY(), this.m_radius, this.getColor());  
  254.               
  255.             this.m_floatingText = new FloatingText(getApplicationContext(), this.getX()-(this.m_radius/2), this  
  256.                     .getY()-this.m_radius, ""this.getPressure(), Color.WHITE );             
  257.               
  258.         }  
  259.           
  260.         public FloatingText getFloatingText(){  
  261.             return m_floatingText;  
  262.         }  
  263.           
  264.         public int getVibrationInterval() {  
  265.             return this.m_vibrationInterval;  
  266.         }  
  267.   
  268.         /** 
  269.          * 정의된 Paint 색 값을 반환하는 메소드입니다. 
  270.          *  
  271.          * @return 
  272.          */  
  273.         public int getColor() {  
  274.             return this.m_color;  
  275.         }  
  276.   
  277.         /** 
  278.          * Paint 색을 할당하는 메소드입니다. 
  279.          *  
  280.          * @param color 
  281.          */  
  282.         public void setColor(int color) {  
  283.             this.m_color = color;  
  284.         }  
  285.   
  286.         /** 
  287.          * 압력 값을 반환하는 메소드입니다. 
  288.          *  
  289.          * @return 
  290.          */  
  291.         public float getPressure() {  
  292.             return this.m_pressure;  
  293.         }  
  294.   
  295.         /** 
  296.          * 압력 값을 정의하는 메소드입니다. 
  297.          *  
  298.          * @param pressure 
  299.          */  
  300.         public void setPressure(float pressure) {  
  301.             this.m_pressure = pressure;  
  302.         }  
  303.   
  304.         /** 
  305.          * 포인터 아이디를 반환하는 메소드입니다. 
  306.          *  
  307.          * @return 
  308.          */  
  309.         public int getPointerId() {  
  310.             return this.m_pointerId;  
  311.         }  
  312.   
  313.         /** 
  314.          * 포인터 인덱스를 반환하는 메소드입니다. 
  315.          *  
  316.          * @return 
  317.          */  
  318.         public int getPointerIndex() {  
  319.             return this.m_pointerIndex;  
  320.         }  
  321.   
  322.         /** 
  323.          * x 좌표값을 반환하는 메소드입니다. 
  324.          *  
  325.          * @return 
  326.          */  
  327.         public float getX() {  
  328.             return this.m_x;  
  329.         }  
  330.   
  331.         /** 
  332.          * y 좌표값을 반환하는 메소드입니다. 
  333.          *  
  334.          * @return 
  335.          */  
  336.         public float getY() {  
  337.             return this.m_y;  
  338.         }  
  339.   
  340.         /** 
  341.          * 도형 인스턴스를 반환하는 메소드입니다. 
  342.          *  
  343.          * @return 
  344.          */  
  345.         public Ball getBall() {  
  346.             return this.m_ball;  
  347.         }  
  348.   
  349.         /** 
  350.          * 각 인스턴스 값을 초기화하는 메소드입니다. 
  351.          */  
  352.         public void setInit() {  
  353.             this.m_pointerId = -1;  
  354.             this.m_pointerIndex = -1;  
  355.             this.m_x = -1;  
  356.             this.m_y = -1;  
  357.             this.m_pressure = -1;  
  358.             this.m_color = Color.GREEN;  
  359.             this.m_ball = null;  
  360.         }  
  361.     }  
  362.   
  363.     /** 
  364.      * 모션 이벤트를 담아두는 ArrayList 인스턴스입니다. 
  365.      */  
  366.     private ArrayList<EventNode> m_aEventNodes = new ArrayList<EventNode>();  
  367.   
  368.     /** 
  369.      * Activity 생성시 접근 메소드 
  370.      *  
  371.      * @see android.app.Activity#onCreate(android.os.Bundle) 
  372.      */  
  373.     @Override  
  374.     public void onCreate(Bundle savedInstanceState) {  
  375.         super.onCreate(savedInstanceState);  
  376.         setContentView(R.layout.main);  
  377.   
  378.         // 레이아웃 인스턴드 할당  
  379.         m_mainLayout = (FrameLayout) this.findViewById(R.id.main);  
  380.   
  381.         // 디버그 텍스트 뷰 인스턴스 할당  
  382.         m_tvDebugText = (TextView) this.findViewById(R.id.debug_text);  
  383.         m_tvDebugText2 = (TextView) this.findViewById(R.id.debug_text2);  
  384.     }  
  385.   
  386.     /** 
  387.      * 터치했을때 반응하는 메소드입니다. 
  388.      *  
  389.      * @see android.app.Activity#onTouchEvent(android.view.MotionEvent) 
  390.      */  
  391.     @Override  
  392.     public boolean onTouchEvent(MotionEvent event) {  
  393.         m_eventCnt = event.getPointerCount();  
  394.   
  395.         m_tvDebugText.setVisibility(View.VISIBLE);  
  396.         m_tvDebugText.setText("Points : " + m_eventCnt  
  397.                 + " / EventNodes : " + m_aEventNodes.size());  
  398.   
  399.         switch (event.getAction()) {  
  400.         // 눌렀을 때  
  401.         case MotionEvent.ACTION_DOWN:  
  402.             drawBall(event);  
  403.             return true;  
  404.   
  405.             // 누르고 이동할 때  
  406.         case MotionEvent.ACTION_MOVE:  
  407.             moveBall(event);  
  408.             return true;  
  409.   
  410.             // 떼었을 때  
  411.         case MotionEvent.ACTION_UP:  
  412.             removeBall();  
  413.   
  414.             m_tvDebugText.setVisibility(View.GONE);  
  415.             return true;  
  416.         }  
  417.   
  418.         return false;  
  419.     }  
  420.   
  421.     /** 
  422.      * 도형 그리는 메소드 
  423.      *  
  424.      * @param event 
  425.      */  
  426.     private void drawBall(MotionEvent event) {  
  427.         removeBall();  
  428.         for (int i = 0; i < m_eventCnt; i++) {  
  429.             EventNode eventNode = new EventNode(event, i);  
  430.             m_aEventNodes.add(eventNode);  
  431.             m_mainLayout.addView(eventNode.getBall());  
  432.             m_mainLayout.addView(eventNode.getFloatingText());  
  433.             ((Vibrator)getSystemService(VIBRATOR_SERVICE)).vibrate(eventNode.getVibrationInterval());  
  434.         }  
  435.   
  436.     }  
  437.   
  438.     /** 
  439.      * 도형 이동 처리 메소드 
  440.      *  
  441.      * @param event 
  442.      */  
  443.     private void moveBall(MotionEvent event) {  
  444.         removeBall();  
  445.         drawBall(event);  
  446.     }  
  447.   
  448.     /** 
  449.      * 도형 제거 처리 메소드 
  450.      */  
  451.     private void removeBall() {  
  452.         int nSize = m_aEventNodes.size();  
  453.         for (int i = 0; i < nSize; i++) {  
  454.             m_mainLayout.removeView(m_aEventNodes.get(0).getBall());  
  455.             m_mainLayout.removeView(m_aEventNodes.get(0).getFloatingText());  
  456.             m_aEventNodes.remove(0);  
  457.         }  
  458.     }  
  459.   
  460. }  

+ main.xml
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:id="@+id/main" android:orientation="vertical"  
  4.     android:layout_width="fill_parent" android:layout_height="fill_parent">  
  5.     <LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent">   
  6.         <TextView android:id="@+id/debug_text2"   
  7.             android:layout_width="wrap_content"  
  8.             android:layout_height="wrap_content"   
  9.             android:gravity="left" />  
  10.         <TextView android:id="@+id/debug_text"   
  11.             android:layout_width="wrap_content"  
  12.             android:layout_height="wrap_content"   
  13.             android:gravity="right"/>  
  14.     </LinearLayout>  
  15. </FrameLayout>  

+ strings.xml
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <resources>  
  3.     <string name="app_name">AndroidMultiTouch</string>  
  4. </resources>  

+ AndroidManifest.xml
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
  3.       package="kr.pe.miksnug"  
  4.       android:versionCode="1"  
  5.       android:versionName="1.0">  
  6.     <application android:icon="@drawable/icon" android:label="@string/app_name">  
  7.         <activity android:name=".MainActivity"  
  8.                   android:label="@string/app_name"  
  9.                   android:theme="@android:style/Theme.NoTitleBar.Fullscreen">  
  10.             <intent-filter>  
  11.                 <action android:name="android.intent.action.MAIN" />  
  12.                 <category android:name="android.intent.category.LAUNCHER" />  
  13.             </intent-filter>  
  14.         </activity>  
  15.   
  16.     </application>  
  17. <uses-permission android:name="android.permission.VIBRATE"></uses-permission>  
  18. </manifest>   
저작자 표시

추가
--------------------------------------------------------------------
안드로이드 데브가이드 사이트에서 매니페스트에 
<uses-permission android:name="android.hardware.touchscreen.multitouch"/>
이 퍼미션도 주란다..
Posted by 컴투