모바일 프로그래밍

안드로이드 스튜디오에서 그림판 만들기

아무 말하는 감자 2021. 4. 10. 15:29

프로젝트명 : SimpleDrawing

설명 : 화면에 터치한 대로 선이 그려지는 그림판이다. 총 네 개의 버튼이 있으며, 세 개는 선의 색을 바꿔주는 기능, 한 개는 clear 버튼으로, 이때까지 그린 그림을 지워주는 기능을 가진다.

 

실행 화면:

 

달토끼 귀.여.워.

전체적인 코드 설명 : 색을 바꾸는 버튼으로 인해 코드를 완전히 다르게 작성해야했다.

                           크게, 계속 해서 선을 redraw해야하는데, 그 전 색을 유지한 path들이 다시 그려야하므로,

                          path들을 저장하는 ArrayList, paint들을 저장하는 ArrayList, 총 두 개를 만들어 포문 속에서 하나씩 

                           꺼내 다시 그려주는 형식이다. 

 

마주했던 난관 : 1. 안드로이드 스튜디오에서 button 색 변경시, background color가 계속 변경이 되질 않았다. 

                     코드로도 design에서도 background color를 변경해줬지만, 화면에서는 적용되지 않았다.

                     구글링 해보니, backgroundTint를 같은 색으로 지정해주면 된다던데, 나의 경우는 안되었다;;

                     그 해결법은 아래 코드 button 생성 부분에 background 속성 변경시, 빨간줄과 같이 입력해줬더니

                     해결되었다.

 

                     2. 아래 화면과 같이 path가 비정상적으로 그려졌다. 

                     어이없게도 이유를 몰랐는데, 조금만 더 생각을 해보니, paint 문제라는 걸 깨달았다.

                    아래 SubActivity(SingleTouchView).java Code에서 파란색 부분을 해주면 이 오류가 고쳐진다.

                   

 

Xml Code:

 

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

<com.example.simpledrawing.SingleTouchView
android:id="@+id/singleTouchView"
android:layout_width="409dp"
android:layout_height="651dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<LinearLayout
android:layout_width="410dp"
android:layout_height="63dp"
android:orientation="horizontal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/singleTouchView"
app:layout_constraintVertical_bias="1.0">

<androidx.appcompat.widget.AppCompatButton
android:id="@+id/btn_black"
android:layout_width="111dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@color/black"
android:backgroundTint="@color/black"
android:onClick="onColorButtonClik"
android:text="Black"
android:textColor="@color/white" />

<androidx.appcompat.widget.AppCompatButton
android:id="@+id/btn_red"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@android:color/holo_red_light"  
android:backgroundTint="@android:color/holo_red_light"
android:onClick="onColorButtonClik"
android:text="Red"
android:textColor="@color/black" />

<androidx.appcompat.widget.AppCompatButton
android:id="@+id/btn_green"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@android:color/holo_green_light"
android:backgroundTint="@android:color/holo_green_light"
android:onClick="onColorButtonClik"
android:text="Green"
android:textColor="@color/black" />

<androidx.appcompat.widget.AppCompatButton
android:id="@+id/btn_clean"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@color/white"
android:backgroundTint="@color/white"
android:onClick="onColorButtonClik"
android:text="Clean"
android:textColor="@color/black" />
</LinearLayout>

</androidx.constraintlayout.widget.ConstraintLayout> 

 

MainActivity.java Code:

//button을 눌렀을 때, 호출되는 onColorButtonClik 메소드 생성.

 

package com.example.simpledrawing;

import androidx.appcompat.app.AppCompatActivity;

import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.os.Bundle;
import android.view.View;

public class MainActivity extends AppCompatActivity {
SingleTouchView singleTouch;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
singleTouch = findViewById(R.id.singleTouchView);
}


public void onColorButtonClik(View view){
switch (view.getId()){
case R.id.btn_black:
singleTouch.setColor(Color.BLACK);
break;
case R.id.btn_green:
singleTouch.setColor(Color.GREEN);
break;
case R.id.btn_red:
singleTouch.setColor(Color.RED);
break;
case R.id.btn_clean:
singleTouch.clearPath();
break;
}
}
}

 

SubActivity(SingleTouchView).java Code:

 

//Arraylist에 path와 paint들을 저장하고 redraw 및 디버깅

 

package com.example.simpledrawing;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

import java.util.ArrayList;

public class SingleTouchView extends View {

private Paint paint = new Paint();
private Path path = new Path(); //stroke

//private static final String TAG = "SingleTouchView";

ArrayList<Path> paths = new ArrayList<Path>();
ArrayList<Paint> paints = new ArrayList<Paint>();

public SingleTouchView(Context context, AttributeSet atts){
super(context,atts);
paint.setStrokeWidth(10.0f);
paint.setColor(Color.BLACK);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setAntiAlias(true);
}

public void setColor(int c){
paint = new Paint();
paint.setColor(c);
paint.setStrokeWidth(10.0f);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setAntiAlias(true);
//paints.add(paint);
invalidate();
//paints.add(paint);
}
public void clearPath(){
//path.reset();
paths.clear();
paints.clear();
invalidate();
}
protected void onDraw(Canvas canvas){
//super.onDraw(canvas);
for(int i=0;i<paths.size();i++) {
//Log.d(TAG,String.valueOf(i));
//Log.d(TAG, String.valueOf(paths.get(i)));
//Log.d(TAG, String.valueOf(paints.get(i).getColor()));
canvas.drawPath(paths.get(i),paints.get(i));
}
//canvas.drawPath(path,p);
//i++;
}
public boolean onTouchEvent(MotionEvent event){
float eventX = event.getX();
float eventY = event.getY();

switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
path = new Path();
path.moveTo(eventX,eventY);
paths.add(path);
paints.add(paint);
break;
case MotionEvent.ACTION_MOVE:
path.lineTo(eventX,eventY);
break;
case MotionEvent.ACTION_UP:
break;
default:
return false;
}
invalidate(); //redraw
return true;
}
}