본문 바로가기

Android/2D 그래픽스

[Android] Event Listener 만들기

View를 만들다보면 View안에서 발생하는 Event를 Activity혹은 기타 클래스에 전달해야 할 상황이 오기도한다. 이미 존재하는 인터페이스 중 쓰임새가 맞는 것이 있다면 바로 사용해도 되겠지만 대개는 성격이 맞지 않는다.

이럴 때 자신만의 Event Listener를 만들어서 사용하면 된다.

OnClickListener, OnItemSelectedListener와 마찬가지로 자작 Listener도 인터페이스로 선언을 한다. View의 이벤트를 전달 받을 Activity혹은 클래스는 해당 인터페이스를 구현하고 그 구현체를 View에 등록을 하게된다. View는 이벤트가 발생한 시점에 등등록된 Listener에게 이벤트가 발생 되었음을 알리게 된다.

package com.cashyalla.graphics;

public interface MyEventListener {

	void onMyEvent(TestDomain testDomain);
	
}

역시 인터페이스 이기 때문에 모두 알다시피 구현체가 없어 간단하다. 발생할 수 있는 이벤트의 수가 늘어나면 선언부의 갯수도 늘어나게 될 것이다. 이 곳에서는 단순 테스트이기 때문에 하나의 메소드만 사용하도록 한다. 

인자도 들어가는 TestDomain클래스는 테스트를 쉽게 하기위해 만들어놓은 클래스이다.


package com.cashyalla.graphics;

import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Region;

public class TestDomain {
	/** 숫자 아이디 */
	private int id;
	/** 이름 */
	private String name;
	/** 버튼의 위치 */
	private Region region;
	/** 색 */
	private int color;
	
	public TestDomain(int id, String name, Rect rect, int color) {
		this.id = id;
		this.name = name;
		region = new Region(rect);
		this.color = color;
	}
	/**
	 * 전달받은 캔버스와 페인트로 사각형을 그린다.
	 * @param canvas
	 * @param paint
	 */
	public void draw(Canvas canvas, Paint paint) {
		if (paint != null) {
			paint.setColor(color);
		}
		
		canvas.drawRect(region.getBounds(), paint);
	}
	/**
	 * 현재 좌표점을 포함하고 있는지 아닌지 돌려준다.
	 * @param x
	 * @param y
	 * @return
	 */
	public boolean contains(int x, int y) {
		return region.contains(x, y);
	}

	/**
	 * @return the id
	 */
	public int getId() {
		return id;
	}

	/**
	 * @return the name
	 */
	public String getName() {
		return name;
	}
	
}


위의 클래스는 단순히 id, name을 가지고있고 Region으로 네모가 그려질 위치를 가진다. 그래고 color값을 내장하고 있어 View로부터 Canvas와 Paint를 전달받아 사각형을 그려준다. 이렇게 draw부분을 분리 하면서 View쪽의 소스를 간결하게 만들 수 있다.

이어서 View의 소스코드이다. 매우 단순하게 Touch의 up이벤트를 받아 클릭 된 TestDomain을 Listener에게 전달하는 역할만을 수행한다.


package com.cashyalla.graphics;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.view.MotionEvent;
import android.view.View;

public class EventView extends View {

	private TestDomain[] testDomain;
	/** 이벤트를 전달 받을 인터페이스 */
	private MyEventListener mListener;
	private Paint mPaint;
	
	public EventView(Context context) {
		super(context);
	}
	
	private void init() {
		testDomain = new TestDomain[4];
		mPaint = new Paint();
		// 객체들을 초기화 시킨다.
		// 위치와 색은 그냥 마음대로..
		for (int i = 0; i < testDomain.length; i++) {
			testDomain[i] = new TestDomain(i, "test domain[" + i + "]", new Rect(i * 70, 10, i * 70 + 60, 70), Color.rgb(i * 60 + 10, i * 60 + 10, i * 60 + 10));
		}
	}
	/**
	 * 이벤트를 전달 받을 리스너를 등록한다.
	 * @param listener
	 */
	public void setMyEventListener(MyEventListener listener) {
		mListener = listener;
	}
	
	@Override
	protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
		super.onLayout(changed, left, top, right, bottom);
		init();
	}
	
	@Override
	protected void onDraw(Canvas canvas) {
		// 사각형 버튼들을 그린다.
		for (TestDomain t : testDomain) {
			t.draw(canvas, mPaint);
		}
	}
	
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		
		int action = event.getAction();
		int x = (int) event.getX();
		int y = (int) event.getY();
		
		if (action == MotionEvent.ACTION_UP) {
			for (TestDomain t : testDomain) {
				// 터치 된 위치에 있는 버튼을 리스너에 전달한다.
				if (t.contains(x, y) && mListener != null) {
					mListener.onMyEvent(t);
				}
			}
		}
		
		return true;
	}
}

마지막으로 Activity이다.Activity에서는 전달받은 TestDomain의 ID와 name만을 Toast를 이용하여 출력하고 있다.


package com.cashyalla.graphics;

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

public class GraphicsActivity extends Activity implements MyEventListener {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        EventView view = new EventView(this);
        view.setMyEventListener(this);
        setContentView(view);
    }
    /**
     * View에서 발생한 이벤트를 전달받는다
     */
	@Override
	public void onMyEvent(TestDomain testDomain) {
		Toast.makeText(this, "id : " + testDomain.getId() + ", name : " + testDomain.getName(), Toast.LENGTH_SHORT).show();
	}
}