8. 그래픽 – 2. onTouchEvent에 따른 원과 선 그리기

이번에는 화면에 생성한 뷰를 터치하였을 때 처리를 위한 onTouchEvent 메서드를 재정의하여 원이나 선을 그리는 간단한 앱을 만들어 보아요.

[그림] Graphic onTouchEvent 실습 실행화면

  LINE을 1, CIRCLE을 2로 정의하고 현재 어떠한 도형을 선택하였는지 기억하는 정적 멤버 필드 dflag를 선언하고 LINE으로 초기 설정합시다.

    final static int LINE=1, CIRCLE=2;
    static int dflag = LINE;

onCreateOptionMenu를 재정의하여 LINE과 CIRCLE 메뉴를 추가합니다. 앞에서는 xml 파일에서 메뉴 아이템을 설정하는 방법을 살펴보았는데 여기에서는 java 소스 코드에서 설정하는 방법입니다.

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);
        menu.add(0,LINE,0,"LINE");
        menu.add(0,CIRCLE,0,"CIRCLE");
        return true;
    }

onOptionsItemSelected 메서드를 재정의하여 선택한 아이템 아이드로 그릴 도형을 기억할 dflag 멤버 값을 설정합니다.

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        dflag = item.getItemId();
        return super.onOptionsItemSelected(item);
    }

View를 기반 클래스로 하여 파생한 MyGraphicView 정적 클래스를 내부에 정의합니다.

    private static class MyGrphicView extends View {
    }

MyGraphicView 클래스에 멤버 필드로 시작 점의 좌표와 끝 점의 좌료를 기억할 멤버 필드를 선언하고 화면 좌표 외부의 값인 -1로 설정하세요.

        int sx=-1;
        int sy = -1;
        int ex = -1;
        int ey = -1;

onTouchEvent 메서드를 재정의합니다. 여기에서는 event의 Action값을 얻어와 ACTION_DOWN일 때는 시작 좌표를 설정하고 ACTION_MOVE 혹은 ACTION_UP일 때는 끝 좌표를 설정합니다.

        @Override
        public boolean onTouchEvent(MotionEvent event) {
            switch (event.getAction()){
                case MotionEvent.ACTION_DOWN: ChangeStartPoint(event); break;
                case MotionEvent.ACTION_MOVE:
                case MotionEvent.ACTION_UP: ChangeEndPoint(event); break;
            }
            return true;
        }

시작 좌표를 변경하는 메서드에서는 event의 getX 메서드와 getY 메서드를 호출하여 얻은 값으로 시작 좌표를 설정합니다.

        private void ChangeStartPoint(MotionEvent event) {
            sx = (int)event.getX();
            sy = (int)event.getY();
        }

끝 좌표를 설정하는 메서드에서도 event의 getX 메서드와 getY 메서드를 호출하여 얻읕 값으로 끝 좌표를 설정합니다. 그리고 무효화 영역을 발생하는 invalidate 메서드를 호출하여 다시 그리게 합니다.

        private void ChangeEndPoint(MotionEvent event) {
            ex = (int)event.getX();
            ey = (int)event.getY();
            this.invalidate();
        }

이제 onDraw 메서드를 재정의하여 그릴 도형에 따라 선 혹은 원을 그립니다.

  @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            Paint paint = new Paint();
            paint.setAntiAlias(true);
            paint.setStrokeWidth(3);
            paint.setStyle(Paint.Style.STROKE);
            paint.setColor(Color.RED);
            int radius = (int)Math.sqrt(Math.pow(ex-sx,2)+Math.pow(ey-sy,2));

            switch (dflag){
                case LINE: canvas.drawLine(sx,sy,ex,ey,paint);break;
                case CIRCLE: canvas.drawCircle(sx,sy,radius,paint); break;
            }
        }

다음은 MainActivity.java 파일의 소스 코드입니다.

package com.example.ehclub.ex_graphic2;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;

public class MainActivity extends AppCompatActivity {
    final static int LINE=1, CIRCLE=2;
    static int dflag = LINE;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(new MyGrphicView(this));
        setTitle("Tiny Paint");
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);
        menu.add(0,LINE,0,"LINE");
        menu.add(0,CIRCLE,0,"CIRCLE");
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        dflag = item.getItemId();
        return super.onOptionsItemSelected(item);
    }

    private static class MyGrphicView extends View {
        int sx=-1;
        int sy = -1;
        int ex = -1;
        int ey = -1;
        public MyGrphicView(Context context){
            super(context);
        }

        @Override
        public boolean onTouchEvent(MotionEvent event) {
            switch (event.getAction()){
                case MotionEvent.ACTION_DOWN: ChangeStartPoint(event); break;
                case MotionEvent.ACTION_MOVE:
                case MotionEvent.ACTION_UP: ChangeEndPoint(event); break;
            }
            return true;
        }

        private void ChangeEndPoint(MotionEvent event) {
            ex = (int)event.getX();
            ey = (int)event.getY();
            this.invalidate();
        }

        private void ChangeStartPoint(MotionEvent event) {
            sx = (int)event.getX();
            sy = (int)event.getY();
        }

        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            Paint paint = new Paint();
            paint.setAntiAlias(true);
            paint.setStrokeWidth(3);
            paint.setStyle(Paint.Style.STROKE);
            paint.setColor(Color.RED);
            int radius = (int)Math.sqrt(Math.pow(ex-sx,2)+Math.pow(ey-sy,2));

            switch (dflag){
                case LINE: canvas.drawLine(sx,sy,ex,ey,paint);break;
                case CIRCLE: canvas.drawCircle(sx,sy,radius,paint); break;
            }
        }
    }
}