Please Enable JavaScript!
Gon[ Enable JavaScript ]

반응형

안드로이드(Android) SurfaceView Thread 를 이용해 화면에 도형표현 하기

 

환경 : Eclipse Mars, Android 4.2.2

 

이전 예제에서 구현한 View 대신 게임등에 많이 쓰이는 SurfaceView Thread 를 조합하여 클릭시 화면에 도형을 표시하는 샘플입니다. SurfaceView View 보다 효율적입니다. 그래서 게임등을 만들 때 많이 사용하죠.

 

 

먼저 SurfaceView 와 인터페이스인 SurfaceHolder.Callback 두개를 상속받습니다. SurfaceHolder.Callback SurfaceView 종료, 시작, 변경등의 이벤트를 감지하기 위해서 입니다. 그러니까 surfaceChanged(), surfaceCreated(), surfaceDestroyed() 는 무조건 구현해야 되는 것이죠. surfaceCreated() thread 의 시작 코드가 있으며 surfaceDestroyed() 에는 thread 의 종료가 있습니다.

 

public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
}

public void surfaceCreated(SurfaceHolder holder) {
	thread.setRunning(true);
	thread.start();
}

public void surfaceDestroyed(SurfaceHolder holder) {
	boolean retry = true;
	thread.setRunning(false);
	while (retry) {
		try {
			thread.join();
			retry = false;
		} catch (InterruptedException e) {
		}
	}
}

 

스크린 터치이벤트에서 도형을 그리기 위한 지금계산을 하게 됩니다. 이곳에 셋팅하는 순간에 drawing = true 바뀌므로 thread run 에서 그림을 그리기 시작하게 되는 것입니다.

 

@Override
public boolean onTouchEvent(MotionEvent event) {
	// return super.onTouchEvent(event);
	int action = event.getAction();
	if (action == MotionEvent.ACTION_MOVE) {
		float x = event.getX();
		float y = event.getY();
		radius = (float) Math.sqrt(Math.pow(x - initX, 2) + Math.pow(y - initY, 2));
	} else if (action == MotionEvent.ACTION_DOWN) {
		initX = event.getX();
		initY = event.getY();
		radius = 1;
		drawing = true;
	} else if (action == MotionEvent.ACTION_UP) {
		drawing = false;
		performClick();
	}

	return true;
}

 

SurfacView 클래스에서 초기화하는 내용은 페인지 정보와 SurfaceThread 객체 생성시 SurfaceHolder 값등을 인수로 넘깁니다.

 

private void init() {
	getHolder().addCallback(this);
	thread = new SurfaceThread(getHolder(), this);

	setFocusable(true); // make sure we get key events

	paint.setStyle(Paint.Style.STROKE);
	paint.setStrokeWidth(3);
	paint.setColor(Color.RED);
}

 

이렇게 해서 만들어진 사용자 정의 SurfaceView 클래스는 다음과 같습니다.

 

public class EventSufaceView extends SurfaceView implements SurfaceHolder.Callback {

	private SurfaceThread thread;

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		// return super.onTouchEvent(event);
		int action = event.getAction();
		if (action == MotionEvent.ACTION_MOVE) {
			float x = event.getX();
			float y = event.getY();
			radius = (float) Math.sqrt(Math.pow(x - initX, 2) + Math.pow(y - initY, 2));
		} else if (action == MotionEvent.ACTION_DOWN) {
			initX = event.getX();
			initY = event.getY();
			radius = 1;
			drawing = true;
		} else if (action == MotionEvent.ACTION_UP) {
			drawing = false;
			performClick();
		}

		return true;
	}

	@Override
	public boolean performClick() {
		return super.performClick();
	}

	public EventSufaceView(Context context) {
		super(context);
		init();
	}

	public EventSufaceView(Context context, AttributeSet attrs) {
		super(context, attrs);
		init();
	}

	public EventSufaceView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		init();
	}

	private void init() {
		getHolder().addCallback(this);
		thread = new SurfaceThread(getHolder(), this);

		setFocusable(true); // make sure we get key events

		paint.setStyle(Paint.Style.STROKE);
		paint.setStrokeWidth(3);
		paint.setColor(Color.RED);
	}

	public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
	}
	
	public void surfaceCreated(SurfaceHolder holder) {
		thread.setRunning(true);
		thread.start();
	}
	
	public void surfaceDestroyed(SurfaceHolder holder) {
		boolean retry = true;
		thread.setRunning(false);
		while (retry) {
			try {
				thread.join();
				retry = false;
			} catch (InterruptedException e) {
			}
		}
	}
}

 

두번째로 Thread 클래스를 상속받아 만든 SurfaceThread 입니다. 생성시 SurfaceHolder EventSurfaceView 객체를 상속받습니다. 그리고 제일중요한 run 함수에서 실질적으로 도형을 그리게 됩니다. 그리기 전에 SurfaceHolder lockCanvas 를 호출하여 잠금니다. 그리고 synchronized 이용하여 그림을 다 그리전에는 아무도 사용하지 못하도록 락을 걸어버립니다.

 

public class SurfaceThread extends Thread {

	private SurfaceHolder mThreadSurfaceHolder;
	private EventSufaceView mThreadSurfaceView;
	private boolean myThreadRun = false;
	private int dX = -100;

	public SurfaceThread(SurfaceHolder surfaceHolder, EventSufaceView surfaceView) {
		mThreadSurfaceHolder = surfaceHolder;
		mThreadSurfaceView = surfaceView;
	}

	public void setRunning(boolean b) {
		myThreadRun = b;
	}

	@Override
	public void run() {
		// super.run();
		while (myThreadRun) {
			Canvas c = null;
			try {
				c = mThreadSurfaceHolder.lockCanvas(null);
				synchronized (mThreadSurfaceHolder) {
					if (drawing) {
						c.drawCircle(initX, initY, radius, paint);
					}
				}
			} finally {
				if (c != null) {
					mThreadSurfaceHolder.unlockCanvasAndPost(c);
				}
			}
		}
	}
}

 

이렇게 Thread 클래스와 SurfacView 클래스를 만들었으면 메인 activity 에서 레이아웃 xml 대신 SurfacView setContentView 의 인수로 넘깁니다.

 

@Override
protected void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	// setContentView(R.layout.activity_surface_view_draw);
	EventSufaceView mySurfaceView = new EventSufaceView(this);
	setContentView(mySurfaceView);
}

 

 

안드로이드(Android) SurfaceView 와 Thread 를 이용해 화면에 도형표현 하기

 

반응형
Posted by 녹두장군1
,