[안드로이드] 그림판 만들기

Updated:

MainActivity.java

public class MainActivity extends AppCompatActivity {}

AppCompatActivity를 상속받는 MainActivity 클래스입니다. 안드로이드 스튜디오에서 제공되는 Support Library는 22.1.0버전 전까지는 ActionBarActivity를 모든 액티비티의 기본 클래스로 정해줬지만 22.1.0버전부터 모든 액티비티는 AppCompatActivity를 기본 클래스로 사용하기 때문에 이 클래스를 상속받았습니다.

@Overrideprotected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.activity_main);
	
}

@Override는 어노테이션을 나타내는 기호입니다. 아래 메소드가 부모 클래스의 메소드를 재정의하였다는 것을 명확하게 컴파일러에게 전달합니다. MainActivity 클래스에 있는 onCreate()메소드는 안드로이드 시스템에 의하여 액티비티가 생성되는 순간에 딱 한번만 호출이 됩니다. 그렇기 때문에 모든 초기화와 사용자 인터페이스 설정이 이 메소드에서 이루어져야 합니다.

super.onCreate(savedInstanceState)문장은 부모 클래스인 AppCompatActivity 클래스의 onCreate()를 호출하는 문장입니다. 부모 클래스가 해야할 일이 있다면 이때 실행됩니다. 또한, super는 상속 관계에서 부모 클래스를 나타내는 키워드 입니다.

setContentView(R.layout.activity_main)라는 메소드는 액티비티의 화면을 설정하는 함수입니다. R클래스 안에 layout이라는 멤버가 있고 그 안의 activity_main을 참조한다는 의미입니다.

onCreate() 메소드에서 캔버스, paint_colors 레이아웃의 아이디를 찾아서 각각 drawView, paintLayout 이라는 변수에 담아주었고, 현재 페인트 색상을 알아 낼 수 있는 변수 currPaint를 만들어 주었습니다. 색상을 선택할 수 있는 레이아웃인 paintLayout은 브러쉬 메뉴를 선택했을 때만 보일 수 있도록 paintLayout.setVisibility(View.INVISIBLE);을 사용하였습니다.

new_btn = findViewById(R.id.new_btn);
draw_btn = findViewById(R.id.draw_btn);
erase_btn = findViewById(R.id.erase_btn);
save_btn = findViewById(R.id.save_btn);

Button.OnClickListener onClickListener = new Button.OnClickListener() {    
    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)    
    @Override    
    public void onClick(View view) {        
        switch (view.getId()) {            
            //새 파일            
            case R.id.new_btn:                
                drawView.setMenu(0);                
                paintLayout.setVisibility(View.INVISIBLE);                
                break;            
                
                //그리기 모드            
                case R.id.draw_btn:                
                    drawView.setMenu(1);                
                    
                    //그리기 모드 버튼을 눌러야 색상 버튼들이 보임                
                    paintLayout.setVisibility(View.VISIBLE);                
                    break;            
                    
                    //지우개 모드            
                    case R.id.erase_btn:                
                    drawView.setMenu(2);                
                    paintLayout.setVisibility(View.INVISIBLE);                
                    break;            
                    
                    //저장 모드            
                    case R.id.save_btn:                
                    drawView.setMenu(1);                
                    paintLayout.setVisibility(View.INVISIBLE);                
                    Toast.makeText(getApplicationContext(), "저장되었습니다.", Toast.LENGTH_SHORT).show();                
                    break;            
                    
                    default:                
                        break;        
                    
                    }     
        }
    };

// 각 Button의 이벤트 리스너로 onClickListener 지정
new_btn.setOnClickListener(onClickListener);
draw_btn.setOnClickListener(onClickListener);
erase_btn.setOnClickListener(onClickListener);
save_btn.setOnClickListener(onClickListener);

각 메뉴 버튼을 아이디와 매칭시킨 후, 클릭 리스너를 구현하는 무명 클래스를 정의하고, 객체를 생성하여 버튼에 지정하였습니다. 무명 클래스(anonymous class)는 몸체는 정의되지만 이름이 없는 클래스 입니다. 무명 클래스를 정의하면서 동시에 객체를 생성합니다. Switch-case문을 사용하여 각각 메뉴 버튼마다 다른 동작을 정의하여주었습니다. 먼저 setMenu는 SingletouchView 클래스의 메소드입니다.

//색상 클릭시 이벤트 발생
public void color_clicked(View view) {    
    if (view != currPaint) {        
        String color = view.getTag().toString();        
        drawView.setColor(color);        
        currPaint = (ImageButton) view;    
    }    
        
    else {        
        drawView.setColor("#00000000");        
        currPaint = (ImageButton) view;    
    }
}

Color_clicked 메소드는 사용자가 색상 버튼을 클릭하면 실행되는 메소드입니다. 사용자가 버튼을 누르면 클릭 이벤트가 발생되고, 클릭 이벤트가 발생하면 레이아웃에 등록된 메소드가 자동으로 호출됩니다. 레이아웃 안의 Button요소에 onClick속성을 추가하였습니다. 현재 색상의 이미지 버튼 값과 사용자가 선택한 색상 버튼 값을 비교해 같지 않으면 선택된 버튼의 태그 값을 읽은 후 문자열로 color변수에 저장합니다. color변수는 브러쉬 색상을 설정합니다.

SingletouchView.java

//View 클래스를 상속받은 SingletouchView 클래스
public class SingletouchView extends View {    
    private Paint paint = new Paint();    
    private Path path = new Path();    
    private int paintColor = 0xFF000000;    
    private Paint canvasPaint;    
    private Canvas drawCanvas;    
    private Bitmap canvasBitmap;
	
}

SingletouchView클래스는 View클래스를 상속받은 클래스입니다. Paint클래스는 색상이나 선의 스타일, 채우기 스타일, 폰트, 앤티에일리어싱 여부 등과 같은 그리기 속성을 가지고 있는 클래스 입니다. Canvas의 메소드는 항상 Paint 객체를 마지막 매개변수로 하여 호출되어야 합니다. Path는 복잡한 기하학적인 경로를 표현합니다. 패스는 직선과 타원, 곡선으로 이루어질 수 있으며 drawPath()메소드를 이용하여 그려집니다.

//생성자
public SingletouchView(Context context, AttributeSet attrs) {    
    super(context, attrs);    
    paint.setAntiAlias(true);    
    paint.setStrokeWidth(10f);    
    paint.setColor(paintColor);    
    paint.setStyle(Paint.Style.STROKE);    
    paint.setStrokeJoin(Paint.Join.ROUND);
}

먼저 생성자를 정의하여 여러가지 초기 값을 설정해주었습니다.

@Overrideprotected void onDraw(Canvas canvas) {    
    //path에 저장된 명령어들을 실행    
    canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);    
    canvas.drawPath(path, paint);
}

onDraw() 콜백 메소드를 정의하였습니다. 이 메소드는 화면을 그리는 작업이 필요할 때마다 안드로이드 프레임워크가 자동으로 호출합니다. 매개변수는 Canvas클래스로 drawRect()나 drawText()와 같은 모든 그리기 메소드를 가지고 있습니다. 만약 애플리케이션을 다시 그려야한다면 invalidate()가 호출하고, 안드로이드는 적절한 시간에 onDraw()를 호출하게 됩니다. Canvas클래스는 Bitmap 객체를 가지고 있으며, 사용자가 캔버스에 그림을 그리면 캔버스가 가지고 있는 비트맵에 그림이 그려집니다.

public void setMenu(int menu) {    
    Log.d("!!singletouchview", String.valueOf(menu));    
    if(menu == 0) {        
        canvasBitmap.eraseColor(Color.WHITE); 	
                
        invalidate();    
    }    
    
    else if(menu == 2) {        
        paint.setColor(0xFFFFFFFF);        
        paint.setStrokeWidth(30f);        
        paint.setStrokeCap(Paint.Cap.SQUARE);    
    }    
    
    else{        
            
    }
}

setMenu()메소드는 MainActivity 클래스에서 호출되는 메소드로 사용자가 메뉴 버튼을 눌렀을 경우 동작을 실행합니다. 0이 매개변수로 넘어올 경우 new_file버튼을 누른 것입니다. 따라서 canvas를 흰색으로 초기화해줍니다. 2가 넘어올 경우 지우개 메뉴를 선택한 것입니다. 그냥 흰색 물감으로 그림을 그릴 경우와 구분을 지어주기 위해 setStrokeWidth(30f);로 브러쉬 크기를 키워주었고, setStrokeCap(Paint.Cap.SQUARE); 로 브러쉬의 모양을 SQUARE모양으로 변경하였습니다.

Activity_main.xml

xml파일에서는 LinearLayout을 사용하여 레이아웃을 정하였습니다. 이미지 버튼을 사용해 메뉴를 좀 더 가시적이게 나타냈습니다. 이미지 버튼은 android:src=”@drawable/파일이름”로 구현할 수 있습니다. 사용할 이미지들은 해당 프로젝트의 res/drawable폴더에 들어가있어야 합니다. 메뉴 버튼 밑에는 그림판인 SingletouchView를 배치하였고 마지막에는 색상을 선택할 수 있는 메뉴 바를 배치하였습니다.

image1

image2

결과

  • 시작 화면

image3


  • brush버튼을 누르면 색상을 고를 수 있는 색상 메뉴가 나옴

image4


  • 지우개는 다른 브러쉬들과 다른 모양인 square로 변경하고 브러쉬 크기를 키움

image5


  • save 버튼을 누르면 “저장 되었습니다.”라는 토스트 메세지가 나옴

image6


  • New 버튼을 누르면 canvas가 초기화

image7

Leave a comment