728x90
반응형
1. 들어가기 전에
1) 개념
- Path 란?
그리기(Draw) 를 할때 사용되는 녀석 중. "덤" 정도로 생각하시면 되겠습니다.
쉽게 말해서 도화지에 우리가 선을 긋는데 그냥 그으면 삐뚤삐뚤 해집니다.
하지만 자를대고 선을 그으면 똑바로 그을수가 있죠. 이때 "자"의 역할을 해주는 녀석을 "Path"라 생각 하시면 되겠습니다.
도화지(Canvas)에 어떤 도형(직선, 곡선, 다각형)을 그리는데 미리 그려진 궤적 정보라고 생각하시면 됩니다.
출처: [초보 플밍지기] https://jwandroid.tistory.com/184
2) 본 문제에서 왜 Path가 필요한가?
- <직접 풀어보기 9-2, 실습 9-1> : 기존 그림 + @ (x) / 매번 새롭게 그림 (o)
- 기존 그림 + @ 를 위해서 '저장할 방법' 필요.
>> 터치 이벤트를 따라 Path 객체에 경로 저장, onDraw()에서 이 객체로 경로 그림.
2. 응용
1) 싱글 터치
<MainActivity.java>
package com.cookandroid.project_drawing2;
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.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.widget.LinearLayout;
public class MainActivity extends AppCompatActivity {
private Paint paint = new Paint();
private Path path = new Path();
private MyPaintView myView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//커스텀뷰 객체 생성 > 레이아웃 자녀로 삽입
myView = new MyPaintView(this);
LinearLayout baseLayout = findViewById(R.id.baseLayout);
baseLayout.addView(myView);
//CLEAR 버튼에 리스너 등록
findViewById(R.id.btnClear).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
path.reset();
myView.invalidate();
}
});
}
private class MyPaintView extends View {
public MyPaintView(Context context) {
super(context);
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(10);
paint.setColor(Color.BLUE);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//캔버스에 경로 그림
canvas.drawPath(path, paint);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
path.moveTo(x, y);
break;
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_UP:
path.lineTo(x, y);
break;
default:
return false;
}this.invalidate();
return true;
}
}
}
2) 색상 선택 그림판
- Path 객체는 색상 미포함.
>> 그림을 별도의 비트맵에 저장, onDraw() 이 비트맵 그리는 방식
<activity_main.xml> - 커스텀 뷰(그림 화면) 만들어 비트맵과 연결
더보기
더보기
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/baseLayout"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#cccccc"
android:gravity="center"
android:orientation="horizontal">
<RadioGroup
android:id="@+id/radioGroup"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<RadioButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/btnRed"
android:text="RED"
android:checked="true"/>
<RadioButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/btnGreen"
android:text="GREEN"/>
<RadioButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/btnBlue"
android:text="BLUE"/>
</RadioGroup>
<Button
android:id="@+id/btnClear"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:text="CLEAR"
android:backgroundTint="@color/purple_500"/>
</LinearLayout>
<!--커스텀뷰, paintLayout-->
<LinearLayout
android:id="@+id/paintLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"/>
</LinearLayout>
<Mainactivity.java>
- 커스텀 뷰 활용, 비트맵에 그림 저장.
(포인트) 비트맵 생성 위해 onSizeChanged()
onDraw()에는 비트맵 그림 불러옴.
package com.cookandroid.project_drawing3;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.RadioGroup;
public class MainActivity extends AppCompatActivity {
private MyPaintView myView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myView = new MyPaintView(this);
((LinearLayout)findViewById(R.id.paintLayout)).addView(myView);
((RadioGroup)findViewById(R.id.radioGroup)).setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup radioGroup, int i) {
switch (i) {
case R.id.btnRed:
myView.mPaint.setColor(Color.RED);
break;
case R.id.btnGreen:
myView.mPaint.setColor(Color.GREEN);
break;
case R.id.btnBlue:
myView.mPaint.setColor(Color.BLUE);
break;
}
}
});
((Button)findViewById(R.id.btnClear)).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
myView.mBitmap.eraseColor(Color.TRANSPARENT);
myView.invalidate();
}
});
}
private class MyPaintView extends View {
private Bitmap mBitmap; //그림 저장할 비트맵
private Canvas mCanvas; //비트맵과 연결된 캔버스
private Path mPath;
private Paint mPaint;
//생성자
public MyPaintView(Context context) {
super(context);
mPath = new Path();
mPaint = new Paint();
mPaint.setColor(Color.RED);
mPaint.setAntiAlias(true);
mPaint.setStrokeWidth(10);
mPaint.setStyle(Paint.Style.STROKE);
}
// onSizeChanged() = View 크기가 변경될 때 호출되는 콜백.
// 뷰 크기 얻어 동일한 크기의 bitmap 생성 위해 썼음.
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
//ARGB가 각 8비트씩 픽셀당 4바이트로 비트맵 형성
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mPath.reset();
mPath.moveTo(x, y);
break;
case MotionEvent.ACTION_MOVE:
mPath.lineTo(x, y);
break;
case MotionEvent.ACTION_UP:
mPath.lineTo(x, y);
//손 떼면 그려짐, mBitmap에 기록
mCanvas.drawPath(mPath, mPaint);
mPath.reset();
break;
}
this.invalidate();
return true;
}
@Override
protected void onDraw(Canvas canvas) {
//지금까지 그려진 내용
canvas.drawBitmap(mBitmap, 0, 0, null);
canvas.drawPath(mPath, mPaint);
}
}
}'모바일 > android' 카테고리의 다른 글
| [안드로이드프로그래밍6판] 명시적 인텐트, 양방향 액티비티 (0) | 2021.12.15 |
|---|---|
| [안드로이드프로그래밍6판] 명시적 인텐트 개념과 예제 (0) | 2021.12.15 |
| [안드로이드프로그래밍6판] 직접 풀어보기 9-1, 9-2, 실습 9-1 (0) | 2021.12.15 |
| [안드로이드프로그래밍6판] (대화 상자) 실습 7-3, 직접 풀어보기 7-3 (0) | 2021.12.11 |
| [안드로이드프로그래밍6판] (컨텍스트 메뉴) 실습 7-2, 직접 풀어보기 7-2 (0) | 2021.10.22 |



