Please Enable JavaScript!
Gon[ Enable JavaScript ]

반응형

안드로이드(Android) SurfaceView 를 이용하여 터치로 이미지 이동시키기 


이 예제는 애니메이션 효과를 보여주며 터치 이벤트가 발생했을 때 클릭 지점이 그림 위라면
누른상태에서 이미지가 이동할수 있도록 구현한것이다.

SurfaceView 를 이용하였으며 스레드를 구현하기 위해 Runnable Implements 하였다.

SurfaceView 를 상속받게 되면 3가지 추상함수를 구현해야되는데 쓰임새는 주석의 설명과 같다.


/** surface 가 변경될때 */
public void surfaceChanged(SurfaceHolder holder, int format,int width,int height){

}
/** surface 가 생성될때 */
public void surfaceCreated(SurfaceHolder holder) {

}
/** surface 가 종료될때 */
public void surfaceDestroyed(SurfaceHolder holder) {

}

이제 그림을 그리기 위한 화면 객체를 생성할 함수가 준비 되었으니 이곳에 그림을 그리는

역할을 할 스레드가 만들어져야한다. 스레드는 Runnable 인터페이스를 이용하여 구현되었다.

public void run() 함수를 override 하여 내부에 필요한 기능을 구현하였다.

 

처음에 객체가 생성될 SurfaceHolder 객체를 리턴받게 된다. 여기에서 이미지를 그릴

도화지에 해당하는 Canvas 가져온다. 가져올때 SurfaceHolder 에서 Canvas 작업이

끝나기 전까지 lock 시키고 끝나고 나면 unlock 시키는데 소스는 다음과 같다

Canvas c = null;
try {
	c = holder.lockCanvas(null);
	synchronized (holder) {
		doDraw(c);
		Thread.sleep(50);
	}
} catch (InterruptedException e) {
	e.printStackTrace();
} finally {
	if (c != null){
		holder.unlockCanvasAndPost(c);
	}
}

그리고 위의 기능은 run 스레드를 수행하는 함수에 들어 있으며, 실질적인 그림작업은

doDraw 라는 함수를 하나 만들어 구현하였다. 내용은 Canvas 객체를 이용해 비트맵이미지를

그리며 text를 쓰는 작업이다.

이미지의 이동은 터치 이벤트를 캡쳐한것중에 MotionEvent.ACTION_MOVE 일때 이미지를

그릴 좌표를 변경시켜준다. 변경된 좌표는 스레드에서 이미지를 그릴 때 적용이 되어

이미지를 터치 지점으로 이동하게 만들어 준다. 그리고 마우스를 Up 했을떄 이동을 멈추게

하였다
@Override
public boolean onTouchEvent(MotionEvent event) {
	int keyAction = event.getAction();
	int x = (int)event.getX();
	int y = (int)event.getY();
	mouseX = x;
	mouseY = y;
	switch (keyAction){
	case MotionEvent.ACTION_MOVE:
		if (bMove){
			moveX = x;
			moveY = y;
		}
		break;
	case MotionEvent.ACTION_UP:
		bMove = false;
		break;
	case MotionEvent.ACTION_DOWN:
		this.checkImageMove(x, y);
		break;
	}
	// 함수 override 해서 사용하게 되면  return  값이  super.onTouchEvent(event) 되므로
	// MOVE, UP 관련 이벤트가 연이어 발생하게 할려면 true 를 반환해주어야 한다.
	return true;
}

이것을 이용해 애니메이션 관련 프로그램에 적용을 하고자 한다. 좀더 개선을 해야겠다는 생각이

팍팍 들긴 하는데 당장은 2가지 밖에 생각이 나질 않는다. 좀더 부드럽게 이미지가 따라 올수

있도록 해야겠다는 것과 애니메이션 효과를 넣어 실제로 물건을 들어 옮기는 것과 같은

느낌이 들도록 구현 하고 싶다.

 

전체소스와 구현 이미지


실행 Activity Main.java

import android.app.Activity;
import android.os.Bundle;

public class Main extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(new AnEventMove(this));
    }

}
AnEventMove.java
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.SurfaceHolder.Callback;

public class AnEventMove extends SurfaceView implements Callback, Runnable {
	private Context mContext;
	private SurfaceHolder holder;
	private Bitmap imgMove;
	private int moveX = 0;
	private int moveY = 0;
	private int imgWidth = 0;
	private int imgHeight = 0;
	private int moveLength = 20;
	private Thread thread = null;
	private Point pImage;
	private Point pWindow;
	private boolean bMove = false;
	private int mouseX = 0;
	private int mouseY = 0;
	
	public AnEventMove(Context context) {
		super(context);
		mContext = context;
		
		// SurfaceHolder Create
		holder = getHolder();
		holder.addCallback(this);
		setFocusable(true);
	}
	/** surface 가 변경될때 */
	public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
		
	}
	/** surface 가 생성될때 */
	public void surfaceCreated(SurfaceHolder holder) {
		// window 크기
		pWindow = new Point();
		pWindow.x = 320;
		pWindow.y = 480;
		
		// 이미지 위치
		pImage = new Point(0, 0);
		Resources res = getResources();
		Bitmap tempBitmap = BitmapFactory.decodeResource(res, R.drawable.excavator);
		imgWidth = 80;
		imgHeight = 70;
		
		// 표시할 위치
		moveX = pWindow.x / 2;
		moveY = pWindow.y / 2;
		
		// 이미지 그리기
		imgMove = Bitmap.createScaledBitmap(tempBitmap, imgWidth, imgHeight, true);
		setClickable(true);
		thread = new Thread(this);
		thread.start();
	}

	public void surfaceDestroyed(SurfaceHolder holder) {
		try { 
			thread.interrupt(); 
		} catch (Exception e) { 
			Log.e(this.getClass().getName(), e.getMessage()); 
		} 
	}

	public void run() {
		// Canvas 의 사이즈
		pWindow.x = getWidth();
		pWindow.y = getHeight();
		
		while (!Thread.currentThread().isInterrupted()) {
			Canvas c = null;
			
			try {
				c = holder.lockCanvas(null);
				synchronized (holder) {
					doDraw(c);
					Thread.sleep(50);
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			} finally {
				if (c != null){
					holder.unlockCanvasAndPost(c);
				}
			}
		}
	}
	
	private void doDraw(Canvas cv){
		
		pImage.x = moveX;
		pImage.y = moveY;
		cv.drawColor(Color.LTGRAY); // 새로그림
		cv.drawBitmap(imgMove, moveX - 40, moveY - 30, null);
		
		// Paint 표시, 그리기 개체
		Paint paint = new Paint();
		paint.setAntiAlias(true);
		paint.setTextSize(16);
		paint.setColor(Color.RED);
		cv.drawText("Move Enable : "+bMove, 0, 400, paint);
		cv.drawText("IMAGE Point : X="+pImage.x+", Y="+pImage.y, 0, 425, paint);
		cv.drawText("Mouse Point : X="+mouseX+", Y="+mouseY, 0, 450, paint);
	}
	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		switch (keyCode){
		case KeyEvent.KEYCODE_DPAD_LEFT:
			if (moveX > 0){
				moveX -= moveLength;
			}
			break;
		case KeyEvent.KEYCODE_DPAD_RIGHT:
			if ((moveX + imgWidth) < pWindow.x){
				moveX += moveLength;
			}
			break;
		case KeyEvent.KEYCODE_DPAD_UP:
			if (moveX > 0){
				moveY -= moveLength;
			}
			break;
		case KeyEvent.KEYCODE_DPAD_DOWN:
			if ((moveY + imgHeight) < pWindow.y){
				moveY += moveLength;
			}
			break;
		case KeyEvent.KEYCODE_DPAD_CENTER:
			break;
		}
		return  super.onKeyDown(keyCode, event);
	}
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		int keyAction = event.getAction();
		int x = (int)event.getX();
		int y = (int)event.getY();
		mouseX = x;
		mouseY = y;
		switch (keyAction){
		case MotionEvent.ACTION_MOVE:
			if (bMove){
				moveX = x;
				moveY = y;
			}
			break;
		case MotionEvent.ACTION_UP:
			bMove = false;
			break;
		case MotionEvent.ACTION_DOWN:
			this.checkImageMove(x, y);
			break;
		}
		// 함수 override 해서 사용하게 되면  return  값이  super.onTouchEvent(event) 되므로
		// MOVE, UP 관련 이벤트가 연이어 발생하게 할려면 true 를 반환해주어야 한다.
		return true;
	}
	/**
	 * 현재 이미지위에 마우스가 위치하는지 판단한다.
	 * @param x
	 * @param y
	 */
	private void checkImageMove(int x, int y){
		int inWidth = 30;
		int inHeight = 20;
		if ((pImage.x - inWidth < x) && (x < pImage.x + inWidth)){
			if ((pImage.y - inHeight < y) && (y < pImage.y + inHeight)){
				bMove = true;
			}
		}
	}
}
반응형
Posted by 녹두장군1
,