안드로이드 Multi-touch Pinch Zoom과 Touch Scroll이 가능한 ImageView 프로그래밍
2010.08.05 23:46 Edit
본래 코드의 출처 없이 사용을 하였습니다. 죄송합니다. 이 글에 나온 코드는 아래 사이트의 코드를 기초로 작성되었습니다.
How to use Multi-touch in Android 2
http://www.zdnet.com/blog/burnette/how-to-use-multi-touch-in-android-2/1747?tag=rbxccnbzd1
아직 실제 안드로이드 폰에서 테스트하지 않았습니다.
10. 8. 6. 11:00 - 확대/축소 오작동을 잡았습니다.
10. 8. 6. 20:00 - 처음 나타날 때, 이미지를 변경할 때 작은 이미지는 가운데, 큰 이미지는 크기에 맞게 축소해서 나오도록 함.
10. 8. 9. 18:00 - 소속된 화면에 변경이 생기면 크기가 리셋되는 문제 수정함.
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.FloatMath;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.ImageView;
public class ViewTouchImage extends ImageView implements OnTouchListener{
// 디버깅 정보
private static final String TAG = "ViewTouchImage";
private static final boolean D = false;
private Matrix matrix = new Matrix();
private Matrix savedMatrix = new Matrix();
private Matrix savedMatrix2 = new Matrix();
private static final int NONE = 0;
private static final int DRAG = 1;
private static final int ZOOM = 2;
private int mode = NONE;
private PointF start = new PointF();
private PointF mid = new PointF();
private float oldDist = 1f;
private static final int WIDTH = 0;
private static final int HEIGHT = 1;
private boolean isInit = false;
public ViewTouchImage(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setOnTouchListener(this);
setScaleType(ScaleType.MATRIX);
}
public ViewTouchImage(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ViewTouchImage(Context context) {
this(context, null);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
if (D) Log.i(TAG, "onLayout");
super.onLayout(changed, left, top, right, bottom);
if (isInit == false){
init();
isInit = true;
}
}
@Override
public void setImageBitmap(Bitmap bm) {
if (D) Log.i(TAG, "setImageBitmap");
super.setImageBitmap(bm);
isInit = false;
init();
}
@Override
public void setImageDrawable(Drawable drawable) {
if (D) Log.i(TAG, "setImageDrawable");
super.setImageDrawable(drawable);
isInit = false;
init();
}
@Override
public void setImageResource(int resId) {
if (D) Log.i(TAG, "setImageResource");
super.setImageResource(resId);
isInit = false;
init();
}
protected void init() {
matrixTurning(matrix, this);
setImageMatrix(matrix);
setImagePit();
}
/**
* 이미지 핏
*/
public void setImagePit(){
// 매트릭스 값
float[] value = new float[9];
this.matrix.getValues(value);
// 뷰 크기
int width = this.getWidth();
int height = this.getHeight();
// 이미지 크기
Drawable d = this.getDrawable();
if (d == null) return;
int imageWidth = d.getIntrinsicWidth();
int imageHeight = d.getIntrinsicHeight();
int scaleWidth = (int) (imageWidth * value[0]);
int scaleHeight = (int) (imageHeight * value[4]);
// 이미지가 바깥으로 나가지 않도록.
value[2] = 0;
value[5] = 0;
if (imageWidth > width || imageHeight > height){
int target = WIDTH;
if (imageWidth < imageHeight) target = HEIGHT;
if (target == WIDTH) value[0] = value[4] = (float)width / imageWidth;
if (target == HEIGHT) value[0] = value[4] = (float)height / imageHeight;
scaleWidth = (int) (imageWidth * value[0]);
scaleHeight = (int) (imageHeight * value[4]);
if (scaleWidth > width) value[0] = value[4] = (float)width / imageWidth;
if (scaleHeight > height) value[0] = value[4] = (float)height / imageHeight;
}
// 그리고 가운데 위치하도록 한다.
scaleWidth = (int) (imageWidth * value[0]);
scaleHeight = (int) (imageHeight * value[4]);
if (scaleWidth < width){
value[2] = (float) width / 2 - (float)scaleWidth / 2;
}
if (scaleHeight < height){
value[5] = (float) height / 2 - (float)scaleHeight / 2;
}
matrix.setValues(value);
setImageMatrix(matrix);
}
@Override
public boolean onTouch(View v, MotionEvent event) {
ImageView view = (ImageView) v;
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
savedMatrix.set(matrix);
start.set(event.getX(), event.getY());
mode = DRAG;
break;
case MotionEvent.ACTION_POINTER_DOWN:
oldDist = spacing(event);
if (oldDist > 10f) {
savedMatrix.set(matrix);
midPoint(mid, event);
mode = ZOOM;
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
break;
case MotionEvent.ACTION_MOVE:
if (mode == DRAG) {
matrix.set(savedMatrix);
matrix.postTranslate(event.getX() - start.x, event.getY() - start.y);
}
else if (mode == ZOOM) {
float newDist = spacing(event);
if (newDist > 10f) {
matrix.set(savedMatrix);
float scale = newDist / oldDist;
matrix.postScale(scale, scale, mid.x, mid.y);
}
}
break;
}
// 매트릭스 값 튜닝.
matrixTurning(matrix, view);
view.setImageMatrix(matrix);
return true;
}
private float spacing(MotionEvent event) {
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return FloatMath.sqrt(x * x + y * y);
}
private void midPoint(PointF point, MotionEvent event) {
float x = event.getX(0) + event.getX(1);
float y = event.getY(0) + event.getY(1);
point.set(x / 2, y / 2);
}
private void matrixTurning(Matrix matrix, ImageView view){
// 매트릭스 값
float[] value = new float[9];
matrix.getValues(value);
float[] savedValue = new float[9];
savedMatrix2.getValues(savedValue);
// 뷰 크기
int width = view.getWidth();
int height = view.getHeight();
// 이미지 크기
Drawable d = view.getDrawable();
if (d == null) return;
int imageWidth = d.getIntrinsicWidth();
int imageHeight = d.getIntrinsicHeight();
int scaleWidth = (int) (imageWidth * value[0]);
int scaleHeight = (int) (imageHeight * value[4]);
// 이미지가 바깥으로 나가지 않도록.
if (value[2] < width - scaleWidth) value[2] = width - scaleWidth;
if (value[5] < height - scaleHeight) value[5] = height - scaleHeight;
if (value[2] > 0) value[2] = 0;
if (value[5] > 0) value[5] = 0;
// 10배 이상 확대 하지 않도록
if (value[0] > 10 || value[4] > 10){
value[0] = savedValue[0];
value[4] = savedValue[4];
value[2] = savedValue[2];
value[5] = savedValue[5];
}
// 화면보다 작게 축소 하지 않도록
if (imageWidth > width || imageHeight > height){
if (scaleWidth < width && scaleHeight < height){
int target = WIDTH;
if (imageWidth < imageHeight) target = HEIGHT;
if (target == WIDTH) value[0] = value[4] = (float)width / imageWidth;
if (target == HEIGHT) value[0] = value[4] = (float)height / imageHeight;
scaleWidth = (int) (imageWidth * value[0]);
scaleHeight = (int) (imageHeight * value[4]);
if (scaleWidth > width) value[0] = value[4] = (float)width / imageWidth;
if (scaleHeight > height) value[0] = value[4] = (float)height / imageHeight;
}
}
// 원래부터 작은 얘들은 본래 크기보다 작게 하지 않도록
else{
if (value[0] < 1) value[0] = 1;
if (value[4] < 1) value[4] = 1;
}
// 그리고 가운데 위치하도록 한다.
scaleWidth = (int) (imageWidth * value[0]);
scaleHeight = (int) (imageHeight * value[4]);
if (scaleWidth < width){
value[2] = (float) width / 2 - (float)scaleWidth / 2;
}
if (scaleHeight < height){
value[5] = (float) height / 2 - (float)scaleHeight / 2;
}
matrix.setValues(value);
savedMatrix2.set(matrix);
}
}
- [2011/01/27] 안드로이드 부트 애니메이션 만들기 (65)
- [2012/02/25] 안드로이드 동영상 플레이어 dice player.apk (12)
- [2012/02/15] 안드로이드 Gallery View 의 잘못된 시선 (8760) *2
- [2012/02/13] iOS5 vs 아이스크림 샌드위치 (2517) *2
- [2012/02/01] 안드로이드 3.2 이상에서 OpenGL ES 참고사항 (2176)
프로그래밍 카테고리의 다른 글
- Tag :
- 안드로이드 , Android , ImageView , Multi-touch , Pinch Zoom , Touch Scroll
Trackbacks 1
-
안드로이드 ImageView 에 Pinch to zoom 추가하기
안드로이드 기본 SDK에서 제공하는 widget... MSDN수준의 문서화를 기대하는 건 아니지만 아무래도 API설명이 좀 부실하다 보니 있는 기능을 몰라서 안 쓰거나 없는 기능인데 찾느라 한참 헤메는 경우가 있는 것 같더군요. 뭐, 기본제공하는 ImageView에 없는 기능인 Touch Scroll/ Pinch to zoom 되게 하느라 좀 헤메서 결과물은 아무도 안 오는 블로그에라도 좀 올려놓으면 편할 듯 하네요. ImgViewTouch.java..
Comments 53
-
출처가 있는 소스같은데 직접 구현하신 것처럼 올려놓으셨네요;
출처를 밝혀주시는 게 나을거 같습니다. 거기엔 소스 단계별 설명도 포함되어 있네요..
원문 : http://www.zdnet.com/blog/burnette/how-to-use-multi-touch-in-android-2/1747?tag=rbxccnbzd1
-
안녕하세요. 블로그 보고 많은 도움을 얻고 있습니다.
위의 소스를 ViewTouch 클래스로 두고,
xml에서 <com.ViewTouchImage.TouchImage android:id=... 로 설정하고
Main.java에서 setContentView로 xml을 지정했습니다.
올려주신 소스로 실행해봤는데
java.lang.InstantiationException: com.ViewTouchImage.TouchImage 가 발생합니다.
아무리 원인을 알아보려 해도 제 지식이 짧아 무엇이 문제인지 감이 잡히질 않습니다.
답변 부탁드립니다. 감사합니다.

안녕하세요.
검색하다 오게 됬는데 많이 배워갑니다.ㅋㅋ
인터넷에 matrix에 관한 정보가 부족하더라구요.
혹시 참고할 사이트 알고계신가요 ?
또 matrix내부에 float 변수들이 있는건가요 ?
각 인덱스마다 어떤 차이가 있는지좀 알고싶은데 가르쳐주시면 감사하겠습니다