View를 만들다보면 View안에서 발생하는 Event를 Activity혹은 기타 클래스에 전달해야 할 상황이 오기도한다. 이미 존재하는 인터페이스 중 쓰임새가 맞는 것이 있다면 바로 사용해도 되겠지만 대개는 성격이 맞지 않는다.
이럴 때 자신만의 Event Listener를 만들어서 사용하면 된다.
OnClickListener, OnItemSelectedListener와 마찬가지로 자작 Listener도 인터페이스로 선언을 한다. View의 이벤트를 전달 받을 Activity혹은 클래스는 해당 인터페이스를 구현하고 그 구현체를 View에 등록을 하게된다. View는 이벤트가 발생한 시점에 등등록된 Listener에게 이벤트가 발생 되었음을 알리게 된다.
역시 인터페이스 이기 때문에 모두 알다시피 구현체가 없어 간단하다. 발생할 수 있는 이벤트의 수가 늘어나면 선언부의 갯수도 늘어나게 될 것이다. 이 곳에서는 단순 테스트이기 때문에 하나의 메소드만 사용하도록 한다.
인자도 들어가는 TestDomain클래스는 테스트를 쉽게 하기위해 만들어놓은 클래스이다.
위의 클래스는 단순히 id, name을 가지고있고 Region으로 네모가 그려질 위치를 가진다. 그래고 color값을 내장하고 있어 View로부터 Canvas와 Paint를 전달받아 사각형을 그려준다. 이렇게 draw부분을 분리 하면서 View쪽의 소스를 간결하게 만들 수 있다.
이어서 View의 소스코드이다. 매우 단순하게 Touch의 up이벤트를 받아 클릭 된 TestDomain을 Listener에게 전달하는 역할만을 수행한다.
마지막으로 Activity이다.Activity에서는 전달받은 TestDomain의 ID와 name만을 Toast를 이용하여 출력하고 있다.
이럴 때 자신만의 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(); } }