안드로이드 개발 질문/답변
(글 수 45,052)
package com.example.zoominzoomout6;
import android.app.Activity; import android.graphics.Matrix; import android.graphics.PointF; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.util.FloatMath; import android.util.Log; import android.view.Menu; import android.view.MotionEvent; import android.view.View; import android.view.View.OnTouchListener; import android.widget.ImageView;
public class MainActivity extends Activity implements OnTouchListener {
// These matrices will be used to move and zoom image
Matrix matrix = new Matrix();
Matrix savedMatrix = new Matrix();
Matrix savedMatrix2 = new Matrix();
private static final String TAG = "Touch" ;
// We can be in one of these 3 states
static final int NONE = 0;
static final int DRAG = 1;
static final int ZOOM = 2;
int mode = NONE;
private static final int WIDTH = 0;
private static final int HEIGHT = 1;
//Remeber some things for zooming
PointF start = new PointF();
PointF mid = new PointF();
float oldDist = 1f;
ImageView view = null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
view = (ImageView) findViewById(R.id.imgView1);
view.setOnTouchListener(this);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN://터치시작(첫번째 터치)
savedMatrix.set(matrix);
start.set(event.getX(), event.getY());
Log.d(TAG, "mode=DRAG" );
mode = DRAG;
break;
case MotionEvent.ACTION_UP://터치종료(첫번째 터치)
case MotionEvent.ACTION_POINTER_UP://터치종료(두번째 터치)
mode = NONE;
Log.d(TAG, "mode=NONE" );
break;
case MotionEvent.ACTION_POINTER_DOWN://터치시작(두번째 터치)
oldDist = spacing(event);
Log.d(TAG, "oldDist=" + oldDist);
if (oldDist > 10f) {
savedMatrix.set(matrix);
midPoint(mid, event);
mode = ZOOM;
Log.d(TAG, "mode=ZOOM" );
}
break;
case MotionEvent.ACTION_MOVE://드래그 중
if (mode == DRAG) {
matrix.set(savedMatrix);
float tx = event.getX() - start.x;
float ty = event.getY() - start.y;
Log.i("msg", "tx,ty\t"+tx+", "+ty);
/*
float[] value = new float[9];
matrix.getValues(value);
// 이미지 크기
Drawable d = view.getDrawable();
if (d == null) break;
int imageWidth = d.getIntrinsicWidth();
int imageHeight = d.getIntrinsicHeight();
int scaleWidth = (int) (imageWidth * value[0]);
int scaleHeight = (int) (imageHeight * value[4]);
*/
//if((tx<-14&ty<77)|(tx<3.9&ty<-53)){
matrix.postTranslate(tx, ty);
//}
}else if (mode == ZOOM) {
float newDist = spacing(event);
Log.d(TAG, "newDist=" + newDist);
if (newDist > 10f) {
matrix.set(savedMatrix);
float scale = newDist / oldDist;
matrix.postScale(scale, scale, mid.x, mid.y);
}
float[] values = new float[9];
matrix.getValues(values);
// 매트릭스 값 튜닝.
matrixTurning(matrix, view);
}
break;
}
// Perform the transformation
view.setImageMatrix(matrix);
return true; // indicate event was handled
}
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;
// 5배 이상 확대 하지 않도록
if (value[0] > 5 || value[4] > 5){
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);
}
} xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ImageView
android:id="@+id/imgView1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:src="@drawable/a"
android:scaleType="matrix"
android:background="@drawable/bg_wood"
/>
</RelativeLayout>
위 소스를 실행하면 이미지 확대 및 축소가 되고, 이미지 이동도 됩니다.
근데 첫화면에서 이미지가 크게 확대된 채로 표시됩니다.
첫화면에서 이미지를 한눈에 볼 수 있게 작게 표시하는 방법을 알고 싶습니다.
그리고 이미지가 이동이 되긴하는데 범위의 제한이 없어서 끝 없이 이동이 됩니다.
예를들어 계속 좌로 움직이면 계속해서 무한대로 좌측으로 움직일 수 있습니다.
이미지가 화면에 표시되지 않아도 말이죠.
이미지가 화면에 표시되는 영역까지만 이동이 되게 하고 싶습니다.
그러니까 이동이 되는 거리는 얼만큼 확대 했느냐에 따라 달라질 것이고
또 얼만큼 축소 했느냐에 따라 또 변하겠죠.
스케일 값을 가지고 어떻게 조건을 걸어주면 될 것 같은데, 쉽게 생각이 나질 않네요.
여러분께 두가지 도움을 요청합니다.
그럼, 오늘도 즐거운 하루 보내세요~^^




이미지가 그려지는 Rect(모든 매트릭스 연산을 마친다음에 최종적으로 그려지는 Rect)...
그리고 실제 View의 Rect(0, 0, width, height)를 가지고 계신다면 얼마든지 계산가능합니다.
viewRect.contains(imageRect) 가 false이면 어딘가 넘어갔다는 겁니다. imageRect를 이동할만큼 offset으로 이동시켜서 contains로 따져보시고
만약 넘어간다면 이전 것으로 원복 하시면 되겠네요.