안드로이드 개발 질문/답변
(글 수 2,584)
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로 따져보시고
만약 넘어간다면 이전 것으로 원복 하시면 되겠네요.