English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Android에서 커스텀 ImageView 컨트롤을 사용하여 이미지의 축소 및 드래그를 구현하는 코드

개요: 커스텀 ImageView 컨트롤을 통해 xml 레이아웃에서 커스텀 컴포넌트를 호출하여 이미지를 확대할 수 있습니다.

/**
* 이미지를 멀티 포인트 터치 확대 및 드래그로 제어할 수 있는 커스텀 ImageView 제어
* 
* @author qiuwanyong
*/
public class MyImageView extends ImageView {
/**
* 초기화 상태 상수
*/
public static final int STATUS_INIT = 1;
/**
* 이미지 확대 상태 상수
*/
public static final int STATUS_ZOOM_OUT = 2;
/**
* 이미지 축소 상태 상수
*/
public static final int STATUS_ZOOM_IN = 3;
/**
* 이미지 드래그 상태 상수
*/
public static final int STATUS_MOVE = 4;
/**
* 이미지를 이동하고 확대/축소 변환하는 데 사용되는 행렬입니다.
*/
private Matrix matrix = new Matrix();
/**
* 보여줄 Bitmap 객체
*/
private Bitmap sourceBitmap;
/**
* 현재 작업 상태를 기록합니다. 선택 가능한 값은 STATUS_INIT, STATUS_ZOOM_OUT, STATUS_ZOOM_IN 및 STATUS_MOVE입니다.
*/
private int currentStatus;
/**
* ZoomImageView 컨트롤의 너비
*/
private int width;
/**
* ZoomImageView 컨트롤의 높이
*/
private int height;
/**
* 두 지문이 모두 스크린에 올라와 있을 때의 중심점의 수평 위치 값을 기록합니다
*/
private float centerPointX;
/**
* 두 지문이 모두 스크린에 올라와 있을 때의 중심점의 수직 위치 값을 기록합니다
*/
private float centerPointY;
/**
* 현재 이미지의 너비를 기록합니다. 이미지가 축소될 때, 이 값도 변동됩니다
*/
private float currentBitmapWidth;
/**
* 현재 이미지의 높이를 기록합니다. 이미지가 축소될 때, 이 값도 변동됩니다
*/
private float currentBitmapHeight;
/**
* 지금까지 지문이 수평 축에서 이동한 위치 값을 기록합니다
*/
private float lastXMove = -1;
/**
* 지금까지 지문이 수직 축에서 이동한 위치 값을 기록합니다
*/
private float lastYMove = -1;
/**
* 지문이 수평 축 위에서 이동한 거리를 기록합니다
*/
private float movedDistanceX;
/**
* 지문이 수직 축 위에서 이동한 거리를 기록합니다
*/
private float movedDistanceY;
/**
* 이미지가 매트릭스 위에 있는横向 위치 값을 기록합니다
*/
private float totalTranslateX;
/**
* 이미지가 매트릭스 위에 있는纵向 위치 값을 기록합니다
*/
private float totalTranslateY;
/**
* 이미지가 매트릭스 위에 있는 총 축소 비율을 기록합니다
*/
private float totalRatio;
/**
* 지문이 이동할 때 생성된 축소 비율을 기록합니다
*/
private float scaledRatio;
/**
* 이미지가 초기화될 때의 축소 비율을 기록합니다
*/
private float initRatio;
/**
* 지금까지 두 지표 간의 거리를 기록합니다
*/
private double lastFingerDis;
/**
* ZoomImageView 생성자 함수, 현재 작업 상태를 STATUS_INIT로 설정합니다。
* 
* @param context
* @param attrs
*/
public MyImageView(Context context, AttributeSet attrs) {
super(context, attrs);
currentStatus = STATUS_INIT;
}
/**
* 보여줄 이미지를 설정합니다。
* 
* @param bitmap
* 보여줄 Bitmap 객체
*/
public void setImageBitmap(Bitmap bitmap) {
sourceBitmap = bitmap;
invalidate();
}
@Override
protected void onLayout(boolean changed, int left, int top, int right,
int bottom) {
super.onLayout(changed, left, top, right, bottom);
if (changed) {
// ZoomImageView의 너비와 높이를 각각 가져옵니다
width = getWidth();
height = getHeight();
}
}
@SuppressLint("NewApi") @Override
public boolean onTouchEvent(MotionEvent event) {
if (initRatio == totalRatio) {
getParent().requestDisallowInterceptTouchEvent(false);
}
getParent().requestDisallowInterceptTouchEvent(true);
}
switch (event.getActionMasked()) {
case MotionEvent.ACTION_POINTER_DOWN:
if (event.getPointerCount() == 2) {
// 화면에 두 손가락이 눌려 있을 때, 두 손가락 간의 거리를 계산합니다
lastFingerDis = distanceBetweenFingers(event);
}
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_MOVE:
if (event.getPointerCount() == 1) {
// 화면에 단지 한 손가락으로 이동할 때만 트래그 상태입니다
float xMove = event.getX();
float yMove = event.getY();
if (lastXMove == -1 && lastYMove == -1) {
lastXMove = xMove;
lastYMove = yMove;
}
currentStatus = STATUS_MOVE;
movedDistanceX = xMove - lastXMove;
movedDistanceY = yMove - lastYMove;
// 경계 검사를 수행하여 이미지를 경계 밖으로 드래그하지 않게 합니다
if (totalTranslateX + movedDistanceX > 0) {}}
movedDistanceX = 0;
} else if (width - (totalTranslateX + movedDistanceX) > currentBitmapWidth) {
movedDistanceX = 0;
}
if (totalTranslateY + movedDistanceY > 0) {
movedDistanceY = 0;
} else if (height - (totalTranslateY + movedDistanceY) > currentBitmapHeight) {
movedDistanceY = 0;
}
// 调用onDraw()方法绘制图片
invalidate();
lastXMove = xMove;
lastYMove = yMove;
} else if (event.getPointerCount() == 2) {
// 有两个手指按在屏幕上移动时,为缩放状态
centerPointBetweenFingers(event);
double fingerDis = distanceBetweenFingers(event);
if (fingerDis > lastFingerDis) {
currentStatus = STATUS_ZOOM_OUT;
}
currentStatus = STATUS_ZOOM_IN;
}
// 进行缩放倍数检查,最大只允许将图片放大4倍,最小可以缩小到初始化比例
if ((currentStatus == STATUS_ZOOM_OUT && totalRatio < 4 * initRatio)
|| (currentStatus == STATUS_ZOOM_IN && totalRatio > initRatio)) {
scaledRatio = (float) (fingerDis / lastFingerDis);
totalRatio = totalRatio * scaledRatio;
if (totalRatio > 4 * initRatio) {
totalRatio = 4 * initRatio;
} else if (totalRatio < initRatio) {
totalRatio = initRatio;
}
// 调用onDraw()方法绘制图片
invalidate();
lastFingerDis = fingerDis;
}
}
break;
case MotionEvent.ACTION_POINTER_UP:
if (event.getPointerCount() == 2) {
// 손가락이 스크린에서 벗어났을 때 일시적인 값을 원래 상태로 되돌립니다
lastXMove = -1;
lastYMove = -1;
}
break;
case MotionEvent.ACTION_UP:
// 손가락이 스크린에서 벗어났을 때 일시적인 값을 원래 상태로 되돌립니다
lastXMove = -1;
lastYMove = -1;
break;
default:
break;
}
return true;
}
/**
* currentStatus의 값에 따라 이미지에 대한 어떤 드로잉 작업을 수행할지 결정합니다.
*/
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
switch (currentStatus) {
case STATUS_ZOOM_OUT:
case STATUS_ZOOM_IN:
zoom(canvas);
break;
case STATUS_MOVE:
move(canvas);
break;
case STATUS_INIT:
initBitmap(canvas);
default:
if (sourceBitmap != null) {
canvas.drawBitmap(sourceBitmap, matrix, null);
}
break;
}
}
/**
* 이미지를 확대 처리합니다.
* 
* @param canvas
*/
private void zoom(Canvas canvas) {
matrix.reset();
// 이미지를 총 확대 비율에 따라 확대합니다
matrix.postScale(totalRatio, totalRatio);
float scaledWidth = sourceBitmap.getWidth() * totalRatio;
float scaledHeight = sourceBitmap.getHeight() * totalRatio;
float translateX = 0f;
float translateY = 0f;
// 현재 이미지 너비가 스크린 너비보다 작다면, 스크린 중앙의横坐标에 따라 가로축으로 확대합니다. 그렇지 않으면 두 지지점의 중앙점의横坐标에 따라 가로축으로 확대합니다
if (currentBitmapWidth < width) {
translateX = (width - scaledWidth) / 2f;
}
translateX = totalTranslateX * scaledRatio + centerPointX
* (1 - scaledRatio);
// 경계 검사를 수행하여 이미지가 확대된 후 수평 방향으로 스크린 밖으로 이동하지 않도록 합니다
if (translateX > 0) {
translateX = 0;
} else if (width - translateX > scaledWidth) {
translateX = width - scaledWidth;
}
}
// 현재 이미지 높이가 스크린 높이보다 작다면, 스크린 중앙의纵坐标에 따라 가로축으로 확대합니다. 그렇지 않으면 두 지지점의 중앙점의纵坐标에 따라 가로축으로 확대합니다.
if (currentBitmapHeight < height) {
translateY = (height - scaledHeight) / 2f;
}
translateY = totalTranslateY * scaledRatio + centerPointY
* (1 - scaledRatio);
// 경계 검사를 수행하여 이미지가 확대 후 수직 방향으로 화면을 벗어나지 않도록 합니다.
if (translateY > 0) {
translateY = 0;
} else if (height - translateY > scaledHeight) {
translateY = height - scaledHeight;
}
}
// 확대 후 이미지를 이동하여 확대 후 중앙 포인트 위치가 변경되지 않도록 합니다.
matrix.postTranslate(translateX, translateY);
totalTranslateX = translateX;
totalTranslateY = translateY;
currentBitmapWidth = scaledWidth;
currentBitmapHeight = scaledHeight;
canvas.drawBitmap(sourceBitmap, matrix, null);
}
/**
* 이미지를 이동 처리를 합니다.
* 
* @param canvas
*/
private void move(Canvas canvas) {
matrix.reset();
// 손가락 이동 거리에 따라 총 기울기 값을 계산합니다.
float translateX = totalTranslateX + movedDistanceX;
float translateY = totalTranslateY + movedDistanceY;
// 이미지를 기존의 확대 비율로 확대합니다.
matrix.postScale(totalRatio, totalRatio);
// 이동 거리에 따라 기울기
matrix.postTranslate(translateX, translateY);
totalTranslateX = translateX;
totalTranslateY = translateY;
canvas.drawBitmap(sourceBitmap, matrix, null);
}
/**
* 이미지를 초기화하는 작업을 수행합니다. 이는 이미지를 중앙에 배치하고, 이미지가 화면의 너비나 높이보다 크면 이미지를 축소하는 것을 포함합니다.
* 
* @param canvas
*/
private void initBitmap(Canvas canvas) {
if (sourceBitmap != null) {
matrix.reset();
int bitmapWidth = sourceBitmap.getWidth();
int bitmapHeight = sourceBitmap.getHeight();
if (bitmapWidth > width || bitmapHeight > height) {
if (bitmapWidth - width > bitmapHeight - height) {}}
// 이미지의 너비가 화면 너비보다 크면, 이미지를 비율로 축소하여 전체적으로 표시할 수 있도록 합니다
float ratio = width / (bitmapWidth * 1.0f);
matrix.postScale(ratio, ratio);
float translateY = (height - (bitmapHeight * ratio)) / 2f;
// 縦方向に移動하여画像を中央に表示します
matrix.postTranslate(0, translateY);
totalTranslateY = translateY;
totalRatio = initRatio = ratio;
}
// 이미지의 높이가 화면 높이보다 크면, 이미지를 비율로 축소하여 전체적으로 표시할 수 있도록 합니다
float ratio = height / (bitmapHeight * 1.0f);
matrix.postScale(ratio, ratio);
float translateX = (width - (bitmapWidth * ratio)) / 2f;
// 가로 좌표 방향으로 이동하여 이미지를 가운데에 표시합니다
matrix.postTranslate(translateX, 0);
totalTranslateX = translateX;
totalRatio = initRatio = ratio;
}
currentBitmapWidth = bitmapWidth * initRatio;
currentBitmapHeight = bitmapHeight * initRatio;
}
// 이미지의 너비와 높이가 모두 화면 너비와 높이보다 작을 때, 이미지를 가운데에 표시합니다
float translateX = (width - sourceBitmap.getWidth()) / 2f;
float translateY = (height - sourceBitmap.getHeight()) / 2f;
matrix.postTranslate(translateX, translateY);
totalTranslateX = translateX;
totalTranslateY = translateY;
totalRatio = initRatio = 1f;
currentBitmapWidth = bitmapWidth;
currentBitmapHeight = bitmapHeight;
}
canvas.drawBitmap(sourceBitmap, matrix, null);
}
}
/**
* 두 손가락 사이의 거리를 계산합니다。
* 
* 두 손가락 사이의 중심 점의 좌표를 계산합니다.
* @return 두 손가락 사이의 거리
*/
@SuppressLint("NewApi") private double distanceBetweenFingers(MotionEvent event) {
float disX = Math.abs(event.getX(0) - event.getX(1event.getY(
event.getX( - float disY = Math.abs(event.getY(0)1event.getY(
)); * return Math.sqrt(disX + disX * disY
}
/**
* disY);
* 
* 두 손가락 사이의 중심 점의 좌표를 계산합니다.
*/
@param event
@SuppressLint("NewApi") private void centerPointBetweenFingers(MotionEvent event) {
float xPoint0 = event.getX(0);
float yPoint0 = event.getY(0);1 float xPoint1);
float yPoint1 = event.getY(1);
centerPointX = (xPoint0 + xPoint1) / 2;
centerPointY = (yPoint0 + yPoint1) / 2;
}
}

레이아웃에서 호출

위에 설명한 것은 저가 여러분께 소개한 안드로이드가 사용자 정의 ImageView 컨트롤을 통해 이미지 확대와 드래그를 구현하는 코드입니다. 여러분이 어떤 질문이나 의문이 있다면 댓글을 남겨 주시기 바랍니다. 저는 즉시 답변을 드리겠습니다. 또한,呐喊 강의 사이트에 대한 여러분의 지지에 깊이 감사드립니다!

안내: 본 문서의 내용은 인터넷에서 가져왔으며, 저작권자는 본사가 아닙니다. 인터넷 사용자가 자발적으로 기여하고 업로드한 내용입니다. 본 사이트는 소유권을 가지지 않으며, 인공 편집을 하지 않았으며, 관련 법적 책임도 부담하지 않습니다. 저작권 문제가 있으신 내용을 발견하신다면 notice#w로 이메일을 보내 주시기 바랍니다.3codebox.com에 (이메일 보내는 경우 #을 @으로 변경하여) 신고를 하시고 관련 증거를 제공하시면, 해당 도용 내용이 확인되면 즉시 삭제됩니다.

추천해드립니다