짱짱해커가 되고 싶은 나

09-1. 그래픽 본문

모바일

09-1. 그래픽

동로시 2021. 2. 23. 17:06

안드로이드는 화면에 선, 원 등의 도형을 그리는 방식을 제공한다.

관련 메소드에서 좌표를 입력해서 그릴 수도 있고, 손가락으로 화면을 터치해서 그릴 수도 있다.

그래픽을 표현할 때는 View 클래스를 재정의하는 형태가 많이 사용된다.

 

* Canvas 클래스 (android.graphics.Canvas)

- 점, 선, 원, 사각형 그리기

- 텍스트 쓰기

- 이미지 출력

- drawPoint(float x, float y, Paint paint) : Paint 개체에 설정된 색상, 두께 등으로 점이 그려진다.

 

* Paint 클래스 (android.graphics.Paint)

- 색상 선택

- 스타일 선택

- 펜 두께 선택

- 글꼴 선택

- setColor() : 색상 지정

 

package com.example.graphic;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Bundle;
import android.view.View;

public class MainActivity extends AppCompatActivity {

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

    }

    private static class MyGraphicView extends View {
        public MyGraphicView(Context context){
            super(context);
        }

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

            Paint paint = new Paint();
            paint.setAntiAlias(true);
            paint.setColor(Color.GREEN);
            canvas.drawLine(10, 10, 300, 10, paint);

            paint.setColor(Color.BLUE);
            paint.setStrokeWidth(5);
            canvas.drawLine(10, 30, 300, 30, paint);

            paint.setColor(Color.RED);
            paint.setStrokeWidth(0);
            paint.setStyle(Paint.Style.FILL);
            Rect rect1 = new Rect(10, 50, 10+100, 50+100);
            canvas.drawRect(rect1, paint);

            paint.setStyle(Paint.Style.STROKE);
            Rect rect2 = new Rect(130, 50, 130+100, 50+100);
            canvas.drawRect(rect2, paint);

            RectF rect3 = new RectF(250, 50, 250+100, 50+100);
            canvas.drawRoundRect(rect3, 20, 20, paint);

            canvas.drawCircle(60, 220, 50, paint);

            paint.setStrokeWidth(5);
            Path path1 = new Path();
            path1.moveTo(10,290);
            path1.lineTo(10+50, 290+50);
            path1.lineTo(10+100, 290);
            path1.lineTo(10+150, 290+50);
            path1.lineTo(10+200, 290);
            canvas.drawPath(path1, paint);

            paint.setStrokeWidth(0);
            paint.setTextSize(30);
            canvas.drawText("안드로이드", 10, 390, paint);
        }
    }
}

onDraw()는 클래스가 생성되거나 무효화(invalidate)되면 호출되는 메소드다.

- Paint.setAntiAlias() : 도형의 끝을 부드럽게 처리

- Paint.setStorkeWidth() : 그려질 도형/글자 외곽선의 두께 설정 (0 == 기본 1px)

- Paint.setStyle() : 그려질 도형의 내부를 채울지 여부 결정 (기본 == FILL)

- Canvas.drawLine(x 시작, y 시작, x 끝, y 끝, Paint)

- Canvas.drawRect(rect, paint)

- Canvas.drawRoundRect(rect, x반지름, y반지름, paint) : 사각형 모서리를 둥글게 처리(x,y 값이 클수록 더 부드럽)

- Canvas.drawCircle(중심x, 중심y, 반지름, paint)

- Canvas.drawPath(path, paint)

- Canvas.drawText(text, x, y, paint)

- Rect 클래스(int 형) 

- RectF 클래스(float 형)

- Path 클래스 : 연결된 여러 점을 가진 클래스

- Path.moveTo() : 해당 점으로 이동

- Path.lineTo() : moveTo()이후 점을 계속 추가

 

package com.example.graphic;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.shapes.OvalShape;
import android.os.Bundle;
import android.view.View;

public class MainActivity extends AppCompatActivity {

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

    }

    private static class MyGraphicView extends View {
        public MyGraphicView(Context context){
            super(context);
        }

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

           Paint paint = new Paint();
           paint.setStrokeWidth(50);
           paint.setStyle(Paint.Style.FILL);
           paint.setColor(Color.BLACK);
           canvas.drawLine(40, 40, 40+500, 40, paint);

           paint.setStrokeCap(Paint.Cap.ROUND);
           canvas.drawLine(40, 130, 40+500, 130, paint);

           RectF rect3 = new RectF(100, 200, 500, 200+200);
           canvas.drawOval(rect3, paint);

            RectF rect4 = new RectF(100, 450, 100+200, 450+200);
            canvas.drawArc(rect4, 45, 90, true, paint);

            Rect rect5 = new Rect(100, 700, 300, 900);
            paint.setColor(Color.BLUE);
            canvas.drawRect(rect5, paint);

            Rect rect6 = new Rect(150, 750, 350, 950);
            paint.setColor(Color.argb(120, 255, 0, 0));
            canvas.drawRect(rect6, paint);

        }
    }
}

- Paint.setStrokeCap() : 선이 끝나는 지점의 모양 설정

- Canvas.drawOval(RectF, paint) : 타원 그리기

- Canvas.drawArc(RectF, 시작 각, 스위핑 각, t/f, paint) : RectF에 맞는 원에서 호(false)/부채꼴(ture)을 그린다.

- Color.argb(투명도, 빨, 초, 파)

* 터치 이벤트

화면에 생성한 뷰를 터치하면 Touch 이벤트가 발생한다.

터치를 구현할 때는 View 클래스의 onTouchEvent()를 오버라이딩한다.

 

- MotionEvent.ACTION_DOWN : 손가락으로 화면을 누르기 시작했을 때

- MotionEvent.ACTION_MOVE : 터치 후 손가락을 움직일 때

- MotionEvent.ACTION_UP : 손가락을 화면에서 뗄 때

- MotionEvent.ACTION_CANCEL : 터치가 취소될 때

 

프로젝트1 : 그림판

- 옵션 메뉴 ( 선 그리기/원 그리기)

- 터치 이벤트로 그리기

 

package com.example.graphic;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.shapes.OvalShape;
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 curShape = LINE;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //setContentView(R.layout.activity_main);
        setContentView(new MyGraphicView(this));
        setTitle("간단 그림판");
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);
        menu.add(0,1,0, "선 그리기");
        menu.add(0,2,0,"원 그리기");
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
        switch(item.getItemId()){
            case 1:
                curShape = LINE;
                return true;
            case 2:
                curShape = CIRCLE;
                return true;
        }
        return super.onOptionsItemSelected(item);
    }

    private static class MyGraphicView extends View{
        int startX = -1, startY = -1, stopX = -1, stopY = -1;

        public MyGraphicView(Context context){
            super(context);
        }

        @Override
        public boolean onTouchEvent(MotionEvent event) {
            switch(event.getAction()){
                case MotionEvent.ACTION_DOWN:
                    startX = (int)event.getX();
                    startY = (int)event.getY();
                    break;
                case MotionEvent.ACTION_MOVE:
                case MotionEvent.ACTION_UP:
                    stopX = (int)event.getX();
                    stopY = (int)event.getY();
                    this.invalidate();
                    break;
            }
            return true;
        }

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

            Paint paint = new Paint();
            paint.setAntiAlias(true);
            paint.setStrokeWidth(5);
            paint.setStyle(Paint.Style.STROKE);
            paint.setColor(Color.RED);

            switch(curShape){
                case LINE:
                    canvas.drawLine(startX, startY, stopX, stopY, paint);
                    break;
                case CIRCLE:
                    int radius = (int)Math.sqrt(Math.pow(stopX - startX, 2) +
                            Math.pow(stopY - startY, 2));
                    canvas.drawCircle(startX, startY, radius, paint);
                    break;
            }
        }
    }

}

ACTION_MOVE와 ACTION_UP을 동일하게 처리하는 이유는 드래그할 때마다 그려지는 선/원이 손가락을 계속 따라다니며 보이는 효과를 주기 위함이다. 화면에서 손가락을 떼면 ACTION_UP이 발생하고 onTouchEvent()를 더 이상 실행하지 않는다.

 

프로젝트2 : 그림판 수정

옵션 메뉴 - 선, 원, 사각형, 서브 메뉴(색상 변경-빨,초,파)

 

package com.example.graphic;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.shapes.OvalShape;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.SubMenu;
import android.view.View;

public class MainActivity extends AppCompatActivity {
    final static int LINE = 1, CIRCLE = 2, RECT = 3;
    final static int RED = 1, GREEN = 2, BLUE = 3;
    static int curShape = LINE;
    static int curColor = RED;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //setContentView(R.layout.activity_main);
        setContentView(new MyGraphicView(this));
        setTitle("간단 그림판");
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);
        menu.add(0,1,0, "선 그리기");
        menu.add(0,2,0,"원 그리기");
        menu.add(0,3,0,"사각형 그리기");
        SubMenu subMenu = menu.addSubMenu("색상 변경 >>");
        subMenu.add(1, 1, 0, "빨강");
        subMenu.add(1,2,0,"초록");
        subMenu.add(1,3,0,"파랑");
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
        switch(item.getGroupId()) {
            case 0:
                switch (item.getItemId()) {
                    case 1:
                        curShape = LINE;
                        return true;
                    case 2:
                        curShape = CIRCLE;
                        return true;
                    case 3:
                        curShape = RECT;
                        return true;
                }
                break;
            case 1:
                switch (item.getItemId()) {
                    case 1:
                        curColor = RED;
                        return true;
                    case 2:
                        curColor = GREEN;
                        return true;
                    case 3:
                        curColor = BLUE;
                        return true;
                }
        }
        return super.onOptionsItemSelected(item);
    }

    private static class MyGraphicView extends View{
        int startX = -1, startY = -1, stopX = -1, stopY = -1;

        public MyGraphicView(Context context){
            super(context);
        }

        @Override
        public boolean onTouchEvent(MotionEvent event) {
            switch(event.getAction()){
                case MotionEvent.ACTION_DOWN:
                    startX = (int)event.getX();
                    startY = (int)event.getY();
                    break;
                case MotionEvent.ACTION_MOVE:
                case MotionEvent.ACTION_UP:
                    stopX = (int)event.getX();
                    stopY = (int)event.getY();
                    this.invalidate();
                    break;
            }
            return true;
        }

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

            Paint paint = new Paint();
            paint.setAntiAlias(true);
            paint.setStrokeWidth(5);
            paint.setStyle(Paint.Style.STROKE);

            switch(curColor){
                case RED:
                    paint.setColor(Color.RED);
                    break;
                case GREEN:
                    paint.setColor(Color.GREEN);
                    break;
                case BLUE:
                    paint.setColor(Color.BLUE);
                    break;
            }

            switch(curShape){
                case LINE:
                    canvas.drawLine(startX, startY, stopX, stopY, paint);
                    break;
                case CIRCLE:
                    int radius = (int)Math.sqrt(Math.pow(stopX - startX, 2) +
                            Math.pow(stopY - startY, 2));
                    canvas.drawCircle(startX, startY, radius, paint);
                    break;
                case RECT:
                    canvas.drawRect(startX, startY, stopX, stopY, paint);
                    break;
            }
        }
    }

}

'모바일' 카테고리의 다른 글

10-1. 액티비티와 인텐트  (0) 2021.02.24
09-2. 이미지  (0) 2021.02.24
08-2. SD 카드 폴더/파일 처리 연습  (0) 2021.02.22
08-1. 파일 처리  (0) 2021.02.22
07-3. 메뉴/토스트/다이얼로그 연습  (0) 2021.02.20
Comments