Android 사용자 정의 view 그림 판 구현 방법
스 크 래 치 효과 도 있 습 니 다.매개 변 수 를 바 꾸 기만 하면 됩 니 다.
사용자 정의 view 는 우선 속성 을 사용자 정의 해 야 합 니 다:
values 아래 attrs.xml 만 들 기:
<!-- -->
<declare-styleable name="DrawImg">
<attr name="PaintColor" /> //
<attr name="PaintWidth" /> //
<attr name="CanvasImg" /> //
</declare-styleable>
<!-- -->
<attr name="PaintColor" format="color" />
<attr name="PaintWidth" format="dimension" />
<attr name="CanvasImg" format="reference" />
아래 세 줄 의 지정 단위 의 코드 를 풀 어 여러 사용자 정의 view 를 사용 할 수 있 습 니 다.다음 에 사용자 정의 view 클래스 계승 view 를 새로 만 들 고 앞의 세 가지 구조 방법 을 다시 씁 니 다.
빨 간 선 표 시 는 안 드 로 이 드 studio 3.0.0 매개 변수 알림 에 대한 새로운 기능 입 니 다.
이 를 통 해 앞의 두 구조 방법 을 모두 세 개의 매개 변수의 구조 방법 을 실현 하도록 한다.
구조 방법 을 간단히 말 하 다.하나의 매개 변수의 구조 방법 은 코드 에서 new 를 사용 할 때 사용 되 며,2 개의 매개 변수의 구조 방법 은 레이아웃 xml 에서 사용 되 며,3 개의 매개 변 수 는 기본적으로 사용자 정의 view 류 에서 사용 되 며,대략 이렇다.
다음은 attrs.xml 에서 TypedArray 를 통 해 사용자 정의 속성 을 추출 합 니 다.
// attrs
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.DrawImg, defStyleAttr, 0);
for (int i = 0; i < a.getIndexCount(); i++) {
int attr = a.getIndex(i);
switch (attr) {
case R.styleable.DrawImg_PaintWidth: //
paintWidth = a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, -1, getResources().getDisplayMetrics()));
break;
case R.styleable.DrawImg_PaintColor: //
paintColor = a.getColor(attr, Color.GREEN);
break;
case R.styleable.DrawImg_CanvasImg: //
hasCanvasImg = a.getResourceId(attr, -1);
break;
}
}
//
if (paintWidth == -1) {
paintWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 20, context.getResources().getDisplayMetrics());
}
// bitmap
if (hasCanvasImg != -1) {
bitmap = BitmapFactory.decodeResource(getResources(), hasCanvasImg);
}
//onMeasure ,onDraw new
path = new Path();
레이아웃 에 사용자 정의 속성 을 사용 하지 않 아 오류 가 발생 하지 않도록 기본 값 을 설정 해 야 합 니 다.사용자 정의 view 키 방법 onMeasure(),onDraw()를 다시 씁 니 다.onMeasure()는 이 사용자 정의 view 의 크기 를 지정 합 니 다.onDraw()는 실시 간 으로 그림 을 그 리 는 데 사 용 됩 니 다.
가장 중요 한 3 가지:캔버스,붓 페인트,경로 Path
코드 가 약간 길 지만 주석 이 완전 하 니 주의해 야 할 것 을 제시 하 세 요.
new Paint()방법 중 paint 는 setXfermode()방법 이 있 습 니 다.이 는 도형 혼합 방식 을 나타 내 며 18 가지 가 있 습 니 다~(아래 그림 보다 ADD 와 OVERLAY 가 많 습 니 다)~그림 한 장 보 여 주세요.여기 서 우 리 는 2 가지 SRC 를 사용한다.IN 과 DSTOUT。
SRC_IN:두 겹 의 교차 부분 을 취하 여 상층 부 를 표시 합 니 다.
DST_OUT:두 층 의 비 교 집합 부분 을 취하 여 아래쪽 을 표시 합 니 다.
솔직히 이렇게 말 해도 이해 하기 어 려 우 니 직접 해 봐 야 겠 어 요.하지만 여기 서 알 면:
SRC 사용IN 이 가 보드 를 그 리 는 효과 가 있어 요.
DST 사용OUT 는 스 크 래 치 효과 가 있어 요.
/**
* onMeasure
* 1) getChildCount(): View ;
* 2) getChildAt(i): i ;
* 3) subView.getLayoutParams().width/height: ;
* 4) measureChild(child, widthMeasureSpec, heightMeasureSpec): View ;
* 5) child.getMeasuredHeight/width(): measureChild() View ;
* 6) getPaddingLeft/Right/Top/Bottom(): ;
* 7) setMeasuredDimension(width, height): 。 ,
* “super. onMeasure(widthMeasureSpec, heightMeasureSpec);” 。
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
/**
* getMode ( 3 ) getSize
*
* EXACTLY: , 100dp、match_parent , size ;
* AT_MOST: wrap_content , size ;
* UNSPECIFIED: ( )。
*
* */
// _
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
// _
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
//
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
//
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
// view
// , , view
if (widthMode == MeasureSpec.EXACTLY) {
width = widthSize;
} else {
if (hasCanvasImg != -1) {
// ,
width = bitmap.getWidth();
} else {
// view
width = 500;
}
}
// view
if (heightMode == MeasureSpec.EXACTLY) {
height = heightSize;
} else {
if (hasCanvasImg != -1) {
height = bitmap.getHeight();
} else {
height = 500;
}
}
// view
setMeasuredDimension(width, height);
//
newPaint();
}
private void newPaint() {
// bitmap
newBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
// bitmap
bmPixels = new int[newBitmap.getWidth() * newBitmap.getHeight()];
//new Canvas, bitmap createBitmap ;
// :IllegalStateException : Immutable bitmap passed to Canvas constructor
canvas = new Canvas(newBitmap);
if (hasCanvasImg == -1) {
// ,
canvas.drawColor(Color.GRAY);
} else {
// view
bitmap = zoomBitmap(this.bitmap, width, height);
canvas.drawBitmap(bitmap, 0, 0, null);
}
//
paint = new Paint();
paint.setColor(paintColor);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(paintWidth);
// , ,
paint.setAntiAlias(true);
// , ,
paint.setDither(true);
// STROKE FILL_OR_STROKE ,
paint.setStrokeCap(Paint.Cap.ROUND);
//
paint.setStrokeJoin(Paint.Join.ROUND);
//
/**
* SRC_IN: 。
*/
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
}
// onDraw ,
@Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(newBitmap, 0, 0, null);
super.onDraw(canvas);
}
// , Bitmap
public static Bitmap zoomBitmap(Bitmap bm, int newWidth, int newHeight) {
//
int width = bm.getWidth();
int height = bm.getHeight();
//
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
// matrix
Matrix matrix = new Matrix();
matrix.postScale(scaleWidth, scaleHeight);
//
return Bitmap.createBitmap(bm, 0, 0, width, height, matrix, true);
}
이것 은 이 view 에 있어 서 비교적 복잡 한 코드 이지 만 기능 은 매우 간단 하 다.우 리 는 두 가지 일 을 했다.1.MeasureSpec.getMode(측정 모드)를 통 해 전체 컨트롤 의 너비 와 높이 를 계산 합 니 다.
2.canvas.drawBitmap 를 통 해 캔버스 에 bitmap 를 그 리 는 동시에 new 는 붓 Paint 를 통 해 색상,굵기 등 속성 을 설정 합 니 다.
주의:
1.onDraw()방법 은 invalidate()를 호출 하거나 보기 가 변 할 때마다 다시 가기 때문에 안에 new 물건 을 넣 을 수 없습니다.
2.int[]유형의 배열 bmPixels 가 있 습 니 다.여기 서 무슨 뜻 인지 대충 말씀 드 리 겠 습 니 다.구체 적 인 설명 은 Bitmap 류 getPixels 와 createBitmap 방법 에 대한 상세 한 설명 에서 말 했 습 니 다.
bmPixels:우 리 는 bitmap 의 너비 에 높이 를 곱 하면 int[]형식의 배열 에 도착 할 수 있 습 니 다.이 배열 은 bitmap 를 구성 하 는 모든 픽 셀 점 입 니 다.특정한 픽 셀 점 이 0 일 때 그 가 색깔 이 없다 는 것 을 설명 합 니 다!0 은 색깔 이 있다 는 뜻 이다.
그림 을 그 리 는 이상 손가락 이동 을 감청 해 야 합 니 다.onTouch Event()방법:
@Override
public boolean onTouchEvent(MotionEvent event) {
int currX = (int) event.getX();
int currY = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// ,
path.moveTo(currX, currY);
break;
case MotionEvent.ACTION_MOVE:
// ,
path.lineTo(currX, currY);
break;
case MotionEvent.ACTION_UP:
}
// ,
canvas.drawPath(path, paint);
// View , draw() , , layout() 。
invalidate();
return true;
}
이것 은 간단 합 니 다.손가락 을 눌 렀 을 때 위 치 를 기록 합 니 다.path.moveto 는 path 에 시작 점 위 치 를 설정 하고 이동 할 때 path.lineTo()방법 으로 경 로 를 기록 하 는 동시에 canvas.drawPath(path,paint)를 사용 하여 직접 그립 니 다.invalidate()는 보기 업 데 이 트 를 알 립 니 다.여기에 쓰 세 요.xml 레이아웃 에서 이 view 를 사용 하면 그림 을 그 릴 수 있 습 니 다.
우리 의 붓 Paint 류 는 색깔,굵기,패턴 등 을 지정 할 수 있 습 니 다.그러면 우 리 는 공개 적 인 방법 을 써 서 이 속성 들 을 동태 적 으로 설정 하여 붓 을 더욱 다양성 있 게 할 수 있 습 니 다.
//
public void setPaintColor(int color) {
//path = new Path();
path.reset();
paint.setColor(color);
}
//
public void setPaintMode(int style) {
//path = new Path();
path.reset();
/**
* SRC_IN: ,
* DST_OUT: ,
*/
if (style == 1) {
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
} else {
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
}
resetCanvaas();
}
//
public void resetCanvaas() {
//path = new Path();
path.reset();
canvas.drawBitmap(bitmap, 0, 0, null);
invalidate();
listener.bitmapChangeListener(bitmap);
}
위의 코드 는 붓 색깔 을 설정 하고,붓 종류 와 캔버스 리 셋 을 설정 합 니 다.왜 모두 new Path 를 사용 해 야 합 니까?새로 경 로 를 열 어 붓 에 게 주지 않 으 면,새로운 색깔 을 설정 하고,예전 의 Path 를 사용 하면,붓 은 원래 의 색깔 을 유지 하 는 것 이 아니 라 예전 의 Path 도 새로운 색깔 로 다시 설정 하기 때 문 입 니 다.이렇게 하면 문제 가 발생 할 수 있 습 니 다.매번 new Path,new 에서 한 번 만 들 고 한 번 의 메모리 를 차지 하 며 피 하 는 방법 을 생각 하지만 본 고 는 그림 을 그 리 는 것 이 중점 이 아니 라 논술 하지 않 습 니 다.path.reset()로 변경 됨
효과 의 오른쪽 상단 은 float 형식의 수 를 보 여 줍 니 다.이것 은 스 크 래 치 모드 에서 부분 이 bitmap 에서 차지 하 는 비율 을 지 웠 습 니 다.onMeasure()방법 에는 int[]유형의 배열 bmPixels 가 있 습 니 다.이때 우 리 는 이 배열 을 이용 하여 이 예 를 들 어야 합 니 다.
onTouchEvent()방법의 case MotionEvent.ACTIONUP 에 코드 추가:
@Override
public boolean onTouchEvent(MotionEvent event) {
int currX = (int) event.getX();
int currY = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// ,
path.moveTo(currX, currY);
break;
case MotionEvent.ACTION_MOVE:
// ,
path.lineTo(currX, currY);
// , bitmap
listener.bitmapChangeListener(newBitmap);
break;
case MotionEvent.ACTION_UP:
// ,
int nullPixel = 0;
newBitmap.getPixels(bmPixels, 0, width, 0, 0, width, height);
for (int i = 0; i < bmPixels.length; i++) {
// 0, 0
if (bmPixels[i] == 0) {
nullPixel++;
}
}
//
listener.showBitmapClear((float) nullPixel / (float) bmPixels.length);
break;
}
// ,
canvas.drawPath(path, paint);
// View , draw() , , layout() 。
invalidate();
return true;
}
new Bitmap.getPixels(bmPixels,0,width,0,0,width,height)가 있 습 니 다.getPixels 방법 에 대한 상세 한 설명 은 new Bitmap 의 모든 픽 셀 점 을 모두 꺼 내 방법 중의 첫 번 째 매개 변수 인 bmPixels 에 넣 는 것 입 니 다.이때,우 리 는 for 순환 을 통 해 bmPixels 배열 을 옮 겨 다 녔 다.0 과 같은 설명 은 색 이 지 워 지지 않 았 다 는 것 이다.그들의 수량 을 통계 하고 그들 이 차지 하 는 비율 을 계산 하면 지 워 진 비율 을 계산 할 수 있다.마찬가지 로 우 리 는 0 과 같은 판단 조건 을 바 꾸 어 그 를 다른 색깔 과 같 게 할 수 있다.그러면 다른 색깔 이 차지 하 는 비례 를 계산 할 수 있다.리 셋 인 터 페 이 스 를 써 서 코드 에서 꺼 내 면 OK 입 니 다.
//
public interface bitmapListener {
// bitmap imageview
void bitmapChangeListener(Bitmap bitmap);
//
void showBitmapClear(float clear);
}
public void addBitmapListener(bitmapListener bitmapListener) {
this.listener = bitmapListener;
}
2 개의 인터페이스 가 있 고,하 나 는 실시 간 으로 비트 맵 을 보 여 주 며,하 나 는 지우 기 비율 을 보 여 줍 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Getting Started with Zend Framework 2 - ViewBy default, the action and view in the controller are one-to-one correspondence, such as HellowordController::indexActio...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.