안드로이드(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; } } } }
'안드로이드 개발' 카테고리의 다른 글
(3) 안드로이드(Android) 의 ImageView 레이아웃 옵션과 사용예제들 - 2 (24) | 2010.08.25 |
---|---|
안드로이드(android) 데이타베이스(DB) sqlite3 다루기 (1) (2) | 2010.08.15 |
안드로이드(android) 탭(TabActivity) 3가지 구현하기 (33) | 2010.08.13 |
Android(안드로이드) 에서 탭을 구현할 때 탭별 색상변경과 아이콘 넣어 디자인 하기 (5) | 2010.08.13 |
Canvas 를 이용해서 화면에 이미지 확대, 축소, 변경하기 (8) | 2010.08.10 |
안드로이드 디자인 색상표 ARGB 값을 알아볼수 있는 플래쉬 파일 (0) | 2010.08.09 |
안드로이드 Intent 를 사용하여 이미지,영상,전화번호부등 가져오기 (1) (7) | 2010.08.07 |
안드로이드에서 단위테스트를 위한 Junit 사용하기 (1) (5) | 2010.08.07 |