android canvas 의 onDraw() 내에서

삼각형, 별, 하트 그리기 예제입니다.

Canvas 내 터치 영역에서 각 도형을 새로 그리는 예제도 TouchEvent 안에 적용되어 있습니다.


참고url

http://android-er.blogspot.kr/2014/05/draw-star-on-canvas.html


    


간단히 도형을 선택하는 버튼과 custom view가 정의 됩니다.

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/bt_triangle"
        android:text="삼각형"/>

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@id/bt_triangle"
        android:id="@+id/bt_star"
        android:text="별"/>

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@id/bt_star"
        android:id="@+id/bt_heart"
        android:text="하트"/>

    <poisonrose.myapplication_canvas.MyView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginTop="10dp"
        android:layout_below="@id/bt_triangle"
        android:id="@+id/my_view"/>

</RelativeLayout>



MainActivity.java

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final MyView my_view = (MyView) findViewById(R.id.my_view);

        Button bt_triangle = (Button) findViewById(R.id.bt_triangle);
        bt_triangle.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                my_view.drawTriangle();
            }
        });
        Button bt_star = (Button) findViewById(R.id.bt_star);
        bt_star.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                my_view.drawStar();
            }
        });
        Button bt_heart = (Button) findViewById(R.id.bt_heart);
        bt_heart.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                my_view.drawHeart();
            }
        });
    }
}

MyView.java

생성자에서는 Paint 와 Path를 초기화 합니다.

실제 도형을 그리는 부분은 onDraw내의 canvas.drawPath() 에서 그리며,

포퍼먼스를 고려하여 항상, path의 reset(), close()를 잘 사용하여야 합니다.

코드내에서 보여지는 x, y 값이 선이 시작하는 부분이며,

TouchEvent에서는 현재 터치값을 불러와서 도형을 그리는 형태로 코드를 작성했습니다.

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

public class MyView extends View {

    Paint m_Paint;
    Path m_Path;
    Canvas m_Canvas;

    enum Mode {
        TRIANGLE,
        STAR,
        HEART
    }

    private Mode mMode;

    private int mViewWidth = 0;
    private int mViewHeight = 0;

    public MyView(Context context) {
        super(context);
        initMyView();
    }

    public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initMyView();
    }

    public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initMyView();
    }

    public void initMyView(){
        m_Paint = new Paint();
        m_Paint.setAntiAlias(true);
        m_Paint.setDither(true);
        m_Paint.setColor(0xFFFF0000);
        m_Paint.setStyle(Paint.Style.STROKE);
        m_Paint.setStrokeJoin(Paint.Join.ROUND);
        m_Paint.setStrokeCap(Paint.Cap.ROUND);
        m_Paint.setStrokeWidth(4);

        m_Path = new Path();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        mViewWidth = MeasureSpec.getSize(widthMeasureSpec);
        mViewHeight = MeasureSpec.getSize(heightMeasureSpec);
        setMeasuredDimension(mViewWidth, mViewHeight);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        m_Canvas = canvas;
        m_Canvas.drawColor(0xFFFFFFFF);

        if(mMode == Mode.HEART) {
            float x = mViewWidth/2;
            float y = mViewHeight/2;
            m_Canvas.rotate(45,x,y);
        }
        // Path 갱신 영역
        m_Canvas.drawPath(m_Path, m_Paint);
    }

    public void drawTriangle() {
        float x = mViewWidth/2;
        float y = mViewHeight/2;
        drawTriangle(x, y);
    }

    public void drawTriangle(float x, float y) {
        mMode = Mode.TRIANGLE;
        int side = 200;  /** 삼각형 크기 */
        int height = 300;
        y = y - height;

        m_Path.reset();

        Point point1_draw = new Point((int)x, (int)y);        // 왼
        Point point2_draw = new Point((int)x-side, (int)y+height);  // 아래
        Point point3_draw = new Point((int)x+side, (int)y+height); // 오른
        m_Path.moveTo(point1_draw.x, point1_draw.y);
        m_Path.lineTo(point2_draw.x, point2_draw.y);
        m_Path.lineTo(point3_draw.x, point3_draw.y);
        m_Path.lineTo(point1_draw.x, point1_draw.y);

        m_Path.close();
        invalidate();
    }

    public void drawStar() {
        float x = mViewWidth/2;
        float y = mViewHeight/2;
        drawStar(x, y);
    }

    public void drawStar(float x, float y) {
        mMode = Mode.STAR;
        int radius = 200;   /** 별 크기 */
        y = y - radius;

        int numOfPt = 5;
        double section = 2.0 * Math.PI/numOfPt;
        int innerRadius = (int) (radius / 2.5);
        m_Path.reset();
        m_Path.moveTo(
                (float)(x + radius * Math.cos(0)),
                (float)(y + radius * Math.sin(0)));
        m_Path.lineTo(
                (float)(x + innerRadius * Math.cos(0 + section/2.0)),
                (float)(y + innerRadius * Math.sin(0 + section/2.0)));
        for(int i=1; i < numOfPt; i++){
            m_Path.lineTo(
                    (float)(x + radius * Math.cos(section * i)),
                    (float)(y + radius * Math.sin(section * i)));
            m_Path.lineTo(
                    (float)(x + innerRadius * Math.cos(section * i + section/2.0)),
                    (float)(y + innerRadius * Math.sin(section * i + section/2.0)));
        }
        m_Path.close();
        invalidate();
    }

    public void drawHeart() {
        float x = mViewWidth/2;
        float y = mViewHeight/2;
        drawHeart(x, y);
    }

    public void drawHeart(float x, float y) {
        mMode = Mode.HEART;
        float length = 200; // 하트 크기

        m_Path.reset();

        m_Path.moveTo(x,y);
        m_Path.lineTo(x-length, y);
        m_Path.arcTo(new RectF(x-length-(length/2),y-length,x-(length/2),y),90,180);
        m_Path.arcTo(new RectF(x-length,y-length-(length/2),x,y-(length/2)),180,180);
        m_Path.lineTo(x,y);

        m_Path.close();
        invalidate();
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float x = event.getX();
        float y = event.getY();
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                touchDraw(x, y);
                break;

            case MotionEvent.ACTION_MOVE:
                touchDraw(x, y);
                break;

            case MotionEvent.ACTION_UP:
                touchDraw(x, y);
                break;
        }
        return true;
    }

    private void touchDraw(float x, float y) {
        if(mMode == Mode.TRIANGLE) {
            drawTriangle(x, y);
        } else if(mMode == Mode.STAR) {
            drawStar(x, y);
        } else if(mMode == Mode.HEART) {
            drawHeart(x, y);
        }
    }
}


+ Recent posts