터치 시 canvas에 선을 그리는 예제 코드를 만들었습니다.
실제 동작은 아래와 같이 진행됩니다.
예제 코드가 아래쪽에 기재되어있으며, 혹시 전체 프로젝트를 보고싶으신 분들을 위해
git 주소를 남기니 git에서 확인하시면 전체적으로 간결하게 보실 수 있습니다.
Git repository URL : github.com/OreoChoi/SimpleDrawApplication
<?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:id="@+id/lo_canvas"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fb_open"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/ic_floating_background"
android:elevation="8dp"
android:layout_marginBottom="15dp"
android:src="@drawable/ic_dir"
app:fabSize="mini"
app:layout_constraintBottom_toTopOf="@id/fb_save"
app:layout_constraintHorizontal_bias="0.9"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"/>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fb_save"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/ic_floating_background"
android:elevation="8dp"
android:layout_marginBottom="15dp"
android:src="@drawable/ic_save"
app:fabSize="mini"
app:layout_constraintBottom_toTopOf="@id/fb_eraser"
app:layout_constraintHorizontal_bias="0.9"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"/>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fb_eraser"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/ic_floating_background"
android:elevation="8dp"
android:layout_marginBottom="15dp"
android:src="@drawable/ic_eraser"
app:fabSize="mini"
app:layout_constraintBottom_toTopOf="@id/fb_pen"
app:layout_constraintHorizontal_bias="0.9"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintVertical_bias="0.76" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fb_pen"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/ic_floating_background"
android:elevation="8dp"
android:src="@drawable/ic_pen"
app:fabSize="mini"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.9"
app:layout_constraintHorizontal_bias="0.9"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
/**
* jhChoi - 201123
* 그리기 화면입니다.
* (그리기, 지우기, 저장, 호출)등이 가능합니다.
*/
public class DrawActivity extends AppCompatActivity {
private DrawCanvas drawCanvas;
private FloatingActionButton fbPen; //펜 모드 버튼
private FloatingActionButton fbEraser; //지우개 모드 버튼
private FloatingActionButton fbSave; //그림 저장 버튼
private FloatingActionButton fbOpen; //그림 호출 버튼
private ConstraintLayout canvasContainer; //캔버스 root view
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_draw);
findId();
canvasContainer.addView(drawCanvas);
setOnClickListener();
}
/**
* jhChoi - 201124
* View Id를 셋팅합니다.
*/
private void findId() {
canvasContainer = findViewById(R.id.lo_canvas);
fbPen = findViewById(R.id.fb_pen);
fbEraser = findViewById(R.id.fb_eraser);
fbSave = findViewById(R.id.fb_save);
fbOpen = findViewById(R.id.fb_open);
drawCanvas = new DrawCanvas(this);
}
/**
* jhChoi - 201124
* OnClickListener Setting
*/
private void setOnClickListener() {
fbPen.setOnClickListener((v)->{
drawCanvas.changeTool(DrawCanvas.MODE_PEN);
});
fbEraser.setOnClickListener((v)->{
drawCanvas.changeTool(DrawCanvas.MODE_ERASER);
});
fbSave.setOnClickListener((v)->{
drawCanvas.invalidate();
Bitmap saveBitmap = drawCanvas.getCurrentCanvas();
CanvasIO.saveBitmap(this, saveBitmap);
});
fbOpen.setOnClickListener((v)->{
drawCanvas.init();
drawCanvas.loadDrawImage = CanvasIO.openBitmap(this);
drawCanvas.invalidate();
});
}
/**
* jhChoi - 201124
* Pen을 표현할 class입니다.
*/
class Pen {
public static final int STATE_START = 0; //펜의 상태(움직임 시작)
public static final int STATE_MOVE = 1; //펜의 상태(움직이는 중)
float x, y; //펜의 좌표
int moveStatus; //현재 움직임 여부
int color; //펜 색
int size; //펜 두께
public Pen(float x, float y, int moveStatus, int color, int size) {
this.x = x;
this.y = y;
this.moveStatus = moveStatus;
this.color = color;
this.size = size;
}
/**
* jhChoi - 201124
* 현재 pen의 상태가 움직이는 상태인지 반환합니다.
*/
public boolean isMove() {
return moveStatus == STATE_MOVE;
}
}
/**
* jhChoi - 201124
* 그림이 그려질 canvas view
*/
class DrawCanvas extends View {
public static final int MODE_PEN = 1; //모드 (펜)
public static final int MODE_ERASER = 0; //모드 (지우개)
final int PEN_SIZE = 3; //펜 사이즈
final int ERASER_SIZE = 30; //지우개 사이즈
ArrayList<Pen> drawCommandList; //그리기 경로가 기록된 리스트
Paint paint; //펜
Bitmap loadDrawImage; //호출된 이전 그림
int color; //현재 펜 색상
int size; //현재 펜 크기
public DrawCanvas(Context context) {
super(context);
init();
}
public DrawCanvas(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public DrawCanvas(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
/**
* jhChoi - 201124
* 그리기에 필요한 요소를 초기화 합니다.
*/
private void init() {
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
drawCommandList = new ArrayList<>();
loadDrawImage = null;
color = Color.BLACK;
size = PEN_SIZE;
}
/**
* jhChoi - 201124
* 현재까지 그린 그림을 Bitmap으로 반환합니다.
*/
public Bitmap getCurrentCanvas() {
Bitmap bitmap = Bitmap.createBitmap(this.getWidth(), this.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
this.draw(canvas);
return bitmap;
}
/**
* jhChoi - 201124
* Tool type을 (펜 or 지우개)로 변경합니다.
* */
private void changeTool(int toolMode) {
if (toolMode == MODE_PEN) {
this.color = Color.BLACK;
size = PEN_SIZE;
} else {
this.color = Color.WHITE;
size = ERASER_SIZE;
}
paint.setColor(color);
}
@Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.WHITE);
if (loadDrawImage != null) {
canvas.drawBitmap(loadDrawImage, 0, 0, null);
}
for (int i = 0; i < drawCommandList.size(); i++) {
Pen p = drawCommandList.get(i);
paint.setColor(p.color);
paint.setStrokeWidth(p.size);
if (p.isMove()) {
Pen prevP = drawCommandList.get(i - 1);
canvas.drawLine(prevP.x, prevP.y, p.x, p.y, paint);
}
}
}
@Override
public boolean onTouchEvent(MotionEvent e) {
int action = e.getAction();
int state = action == MotionEvent.ACTION_DOWN ? Pen.STATE_START : Pen.STATE_MOVE;
drawCommandList.add(new Pen(e.getX(), e.getY(), state, color, size));
invalidate();
return true;
}
}
}
[안드로이드 개발자 면접] 경험 정리 (0) | 2020.10.28 |
---|---|
[안드로이드] 카카오톡 이모티콘에 대해 (0) | 2020.05.19 |
[안드로이드] 안드로이드 JAR 생성 가이드 (0) | 2020.05.19 |
[안드로이드] 안드로이드 AAR 생성 가이드 (0) | 2020.05.19 |
[안드로이드] Google Play 스토어 검색 최적화 (1) | 2020.05.18 |