반응형

안드로이드 스튜디오 멀티 터치 공식 설명 부분 참고하세요

https://developer.android.com/training/gestures/multi?hl=ko 

 

아래소스는 멀티터치를 처음 접하시는 분에게 이해를 돕고자 완전 기초 적인 부분만 다루었습니다.

터치 2회.. 손가락 두 개가 터치했을 때만의 예제입니다.

 

빨간색 원은 처음 손가락으로 터치했을 때 움직이게 되고, 노란색 원은 두 번째 손가락을 터치했을 때 움직이게 됩니다.

 

앱의 기초적이 뼈대를 만들 때 미리 이 부분을 고려해서 만들어 놓으면 좋습니다. 싱글 터치만 생각하다 멀티 터치를 써야 하는 때가 와서 막상 적용하려고 하면 소스는 방대해지고 얽히고설켜서 고생할 가능성이 많습니다.

 

예제 설명에서 이리저리 소스가 많아지면 이해하기만 힘들다고 생각합니다.아래 예제는 완전 기본으로 멀티 터치가 어떻게 실행되는지만 보여주는 초 간단 예제입니다

 

에뮬레이터에서는 멀티 터치가 동시에 이루어지므로 실제 기기에서 테스트해야 하고, 멀티 터치 중 처음 터치한 손가락을 때었을 때! 두 번째 한 터치 노란 원 이, 첫 번째 빨간 원으로 바뀌는데 이 부분은 방치한 상태입니다. 실제 테스트 해보시면 이해가실듯

 

하단 추가설명 부분을 읽어보시고 테스트를 해보면  윗부분의 처리는 문제없으리라 생각합니다.

 

안드로이드 스튜디오 실행 후 Empty Activity 만들고 SHIFT+F10 눌러서 앱을 빌드&실행할 수 있다는 전제하에 소스에 주석만 달았습니다.

 

안드로이드 스튜디오 초간단 멀티 터치 코틀린 예제

 

package com.bjstudio.myapplication
 
import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.os.Bundle
import android.util.Log
import android.view.MotionEvent
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.MotionEventCompat
import kotlin.concurrent.timer
 
val circleX = FloatArray(2)    //첫번째0,두번째1 - 터치한 위치 기억 X
val circleY = FloatArray(2) //첫번째0,두번째1 - 터치한 위치 기억 Y
const val circleRa=200f        //원 반지름
 
class MainActivity : AppCompatActivity() {
    
    private lateinit var GameViewScr:TheGameViewer //원 출력할 화면 선언
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        GameViewScr=TheGameViewer(this)      //여기에 화면에 터치한 빨간색 원과 노란색 원을 출력
        setContentView(GameViewScr)
    }
    
    //------------------------------------------------------------------
    //화면을 그리는 부분,최초 실행시 호출되며 invalidate() 로 재호출 할수 있다
    //------------------------------------------------------------------
    private class TheGameViewer(context: Context): View(context) {
        override fun onDraw(canvas: Canvas) {
            super.onDraw(canvas)
            
            val paint = Paint()
            
            canvas.drawColor(Color.WHITE)    //바탕 화면 흰색
            
            //첫번째 빨간원(손가락 한개만 터치했을때 출력 함)
            paint.color = Color.RED
            canvas.drawCircle(circleX[0],circleY[0], circleRa, paint)
            
            //두번째 노란원(손가락 두개가 터치했을때 출력 함)
            paint.color = Color.YELLOW
            canvas.drawCircle(circleX[1],circleY[1], circleRa, paint)
 
        }
        
        //------------------------------------------------------------------
        //화면 멀티 터치 기본 예제
        //------------------------------------------------------------------
        override fun onTouchEvent(event: MotionEvent): Boolean {
            
            val acount=event.pointerCount    //터치한 갯수 값이 = 1 이면 손가락 하나만
// = 2 라면 터치한 손가락이 2

            //val aindex=MotionEventCompat.getActionIndex(event) //액션 인덱스 받음 여기선 사용 x
 
            var aID=event.getPointerId(0)    //첫번째 터치한 이벤트 ID 받음
            event.findPointerIndex(aID).let { pointerIndex ->
                circleX[0= event.getX(pointerIndex)    //첫번째 터치 또는 이동 좌표를 입력
                circleY[0= event.getY(pointerIndex)    //빨간원 좌표
            }
            
            if (acount>1){ //두번째 터치가 있다면
                aID=event.getPointerId(1) //두번째 터치한 이벤트 ID 받음
                event.findPointerIndex(aID).let { pointerIndex ->    
                    circleX[1= event.getX(pointerIndex) //두번째 터치 또는 이동 좌표를 입력           
                    circleY[1= event.getY(pointerIndex) //노란원 좌표
                }
            }
            
            
            when (event.actionMasked) {
                MotionEvent.ACTION_DOWN ->{ //화면 최초 터치시 만,처음 손가락으로 터치시만 이벤트 발생
                   invalidate()            //OnDraw 호출하게..화면 갱신
                }
                MotionEvent.ACTION_POINTER_DOWN ->//처음 터치 외에 멀티 터치,두번째 터치시 이벤트 발생
                    invalidate()
                }
                MotionEvent.ACTION_MOVE->{         //터치후 이동시
                    invalidate()
                }
                MotionEvent.ACTION_UP ->{}        //터치 끝난 경우 이벤트,손가락을 모두 땟을때 이벤트
                MotionEvent.ACTION_POINTER_UP ->{}//터치한 손가락 2개 이상에서(멀티터치) 하나의 손가락을 땠을때
                MotionEvent.ACTION_OUTSIDE -> {}  //뷰 경계를 벗어 났을시
                MotionEvent.ACTION_CANCEL -> {}   //제어권을 손실 (빼앗김),터치 종료
            }
            
            return true
        }
    }
    
}
 

 

※  추가 설명

위에서 사용하지 않는 변수

val aindex=MotionEventCompat.getActionIndex(event)
의 역활은 

MotionEvent.ACTION_POINTER_UP ->{}

이벤트에서  멀티 터치 중 몇 번째 터치가 화면에서 때어졌는지 판별하기 위해 사용됩니다. 

만일 멀티 터치 중 첫 번째 터치한 손가락을 떼면  aindex = 0 값이 옵니다.

만일 멀티 터치 중 두 번째 터치한 손가락을 떼면  aindex = 1 값이 옵니다

 

MotionEvent.ACTION_POINTER_DOWN ->{}

에서는

멀티 터치 중 처음에 터치한 손가락을(빨간 원) 때었다, 다시 터치하면  aindex = 0 값이 옵니다.

멀티 터치 중 두 번째 터치한 손가락을(노란 원) 때었다, 다시 터치하면  aindex = 1 값이 옵니다.

첫번째 손가락만 터치 중, 두번째 손가락을 터치할때도  aindex = 1 값이 옵니다.


주의할 것은 처음에 손가락 두개로 멀티 터치한 후, 첫 번째 터치(빨간 원)에 손을 떼면, 노란 원의 터치가 0번 위치로 옮겨 저서,  circleX[0],circleY[0]의 값을 참조해서 빨간 원을 움직이게 됩니다. (유저 입장에선 노란 원이 움직이여야 합니다)

 

그 상태에서 다시 첫번째 손가락으로 터치해서, 멀티 터치가 되면 새로 터치한 부분은(빨간 원) [0] 번 좌표로, 원래 두 번째 터치는 다시 [1] 번좌표로 자동으로 이동하게 됩니다.

 

이부분만 신경써서 코딩하면 될것 같습니다.

 

2개 이상의 멀티 터치도 처리 가능합니다.

 

최대한 쉽게 쓰려고 했지만, 실제 소스를 테스트해보시고 조금 고민해 보시면 이해가 가실 듯합니다.


아래 코딩은 위 소스를 계량해서 

터치한 두개의 원 중  첫번째 터치한 손가락을 때어도 두번째 터치한 부분이 원래그대로 노락색 원이 유지되겠금 작동한 예 입니다. 

 

 

 


val circleX = FloatArray(2)  //터치한 위치 기억 X,Y
val circleY = FloatArray(2)

var vStopTouchX=0f //멀티 터치중 첫번째 터치에서 손을 때면 두번째가 첫번째 터치로 바뀌는데
var vStopTouchY=0f //그때 빨간색 원 좌표를 보관해 화면에 그리도록한다

const val circleRa=200f    //원 반지름

var vindex=0

var vTouchChaged=false

class MainActivity : AppCompatActivity() {
 
 private lateinit var GameViewScr:TheGameViewer //출력할 화면 객체 선언?!
 
 override fun onCreate(savedInstanceState: Bundle?) {
  super.onCreate(savedInstanceState)
  setContentView(R.layout.activity_main)
  
  GameViewScr=TheGameViewer(this)   //따로 출력 설정
  setContentView(GameViewScr)
 }
 
 //------------------------------------------------------------------
 //화면을 그리는 부분
 //------------------------------------------------------------------
 private class TheGameViewer(context: Context): View(context) {
  override fun onDraw(canvas: Canvas) {
   super.onDraw(canvas)
   
   val paint = Paint()
   
   canvas.drawColor(Color.WHITE)  //바탕 화면 흰색
   
   if (vTouchChaged) { //멀티 터치중에 빨간색(첫번째 터치)의 손가락을 먼저 때었다
    //두번째 터치가 첫번째 터치로 변하므로 첫번째 터치가 계속 노란색이 되게
    paint.color = Color.YELLOW
    canvas.drawCircle(circleX[0],circleY[0], circleRa, paint)
    
    // 빨간원
    paint.color = Color.RED
    canvas.drawCircle(vStopTouchX,vStopTouchY, circleRa, paint)
    
   } else {
   
    //v1Touch-0 정상 순서 터치 동자,,1 멀티 터치중 빨간색 첫번째 터치를 먼저 때었을때
    //첫번째 빨간원
    paint.color = Color.RED
    canvas.drawCircle(circleX[0],circleY[0], circleRa, paint)
   
    //두번째 노란원
    paint.color = Color.YELLOW
    canvas.drawCircle(circleX[1],circleY[1], circleRa, paint)
   }
   
   
   paint.color = Color.BLACK
   paint.setTextSize(100f)
   
  }
  
  //------------------------------------------------------------------
  //화면을 멀티 터치 기본 예제
  //------------------------------------------------------------------
  override fun onTouchEvent(event: MotionEvent): Boolean {
   
   val acount=event.pointerCount  //터치한 갯수(1..손가락 하나만,,2..손가락 두개 터치)
   vindex=MotionEventCompat.getActionIndex(event) //어떤 액션이지 받음

   
   var aID=event.getPointerId(0) //첫번째 처음 터치라면 이벤트 ID 받음
   event.findPointerIndex(aID).let { pointerIndex ->
    circleX[0] = event.getX(pointerIndex)  //첫번째 터치 좌표를 입력
    circleY[0] = event.getY(pointerIndex)  //빨간원 좌표
   }
   
   if (acount>1){ //두번째 터치가 있다면
    
    aID=event.getPointerId(1) //첫번째 처음 터치라면 이벤트 ID 받음
    event.findPointerIndex(aID).let { pointerIndex ->  //두번째 터치 좌표를 입력
     circleX[1] = event.getX(pointerIndex)  //노란원
     circleY[1] = event.getY(pointerIndex)
    }
   }
   
   
   when (event.actionMasked) {
    MotionEvent.ACTION_DOWN ->{     //화면 최초 터치시 만...
     invalidate()           //OnDraw 호출하게..화면 갱신
    }
    MotionEvent.ACTION_POINTER_DOWN ->{ //처음 터치 외에 멀티 터치시 추가적인 작업 처리
     
     
     if (vTouchChaged){ //다시 터치 했는데 이미 첫번째 터치가 노란색 원 조종으로 바뀌어 움직이고 있었다면
      //vindex 값은 0번밖에 안나온다,,0번을 첫번째 새로 터치했으니까
      //첫번째 손을 때면 , 두번째 터치가 첫번째 터치로 되지만, 다시 그상태에서 터치하면
      //첫번째 터치가 (빨간색) 원래대로,0 두번째 터치가 1이 된다.좌표 변경 필요 없음
      vTouchChaged=false //원래되로
     }
     
     invalidate()
    }
    MotionEvent.ACTION_UP ->{       //터치 끝난 경우 작업
     vTouchChaged=false //터치가 모두 제거 됐으므로 초기화
     invalidate()
    }
    MotionEvent.ACTION_POINTER_UP ->{  //손가락 2개 이상에서 손가락을 땠을때
                      //여기서 터치가 때어질땐 두손가락중 하나가 때어진것
//      Log.d("xxxx vindex", vindex.toString())
     if (vindex==0){ //손을 땐 터치가 0 번(빨간색으라면),두번째 터치(노란색을 때면 ==1)
      vTouchChaged=true //두번쩌 터치가 첫번째로 바꼈다..그상태로 다시 손가락을 터치하면 원상태로 된다
      
      //노란색이 첫번째 터치로 바뀌므로, 빨간색 원이 2번째 터치 좌표로 옮겨서 원을 그리게
      vStopTouchX=circleX[0] //빨간색 원을 그리도록 좌표를 보관
      vStopTouchY=circleY[0]
     }
     
     invalidate()
     
    }
    MotionEvent.ACTION_MOVE->{       //터치후 이동시
     //터치하고 움직일 좌표값은 위에서 이미 입력 되므로 그값을 참고 하면 된다
     invalidate()
    }
    MotionEvent.ACTION_OUTSIDE -> {} //뷰 경계를 벗어 났을시
    MotionEvent.ACTION_CANCEL -> {  //제어권을 손실 (빼앗김),터치 종료
     vTouchChaged=false       //터치가 모두 제거 됐으므로 초기화
    }
   }
   
   return true
  }
 }
 
}
반응형

+ Recent posts