我在布局中有一个ImageView,并在ImageView上设置OnTouchListener来拖动ImageView。它工作得很好。我的问题是如何防止将ImageView移出布局范围?
这是我的代码:
活动类:
public class RepositionTestActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.reposition_test_layout);
ImageView imageView = (ImageView)findViewById(R.id.android);
imageView.setOnTouchListener(new Touch());
}
}
触摸课程:
public class Touch implements OnTouchListener {
private static final int NONE = 0;
private static final int DRAG = 1;
private static final int ZOOM = 2;
private static final float MIN_ZOOM = 1f;
private static final float MAX_ZOOM = 5f;
private Matrix matrix = new Matrix();
private Matrix savedMatrix = new Matrix();
private PointF start = new PointF();
private PointF mid = new PointF();
private int mode = NONE;
private float oldDistance = 1f;
public boolean onTouch(View view, MotionEvent event) {
ImageView imageView = (ImageView)view;
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:
oldDistance = spacing(event);
if(oldDistance > 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 newDistance = spacing(event);
if(newDistance > 10f) {
matrix.set(savedMatrix);
float scale = newDistance / oldDistance;
float[] values = new float[9];
matrix.getValues(values);
float currentScale = values[Matrix.MSCALE_X];
if(scale * currentScale > MAX_ZOOM)
scale = MAX_ZOOM / currentScale;
else if (scale * currentScale < MIN_ZOOM)
scale = MIN_ZOOM / currentScale;
matrix.postScale(scale, scale, mid.x, mid.y);
}
}
break;
}
imageView.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) {
point.set((event.getX(0) + event.getX(1)) / 2, (event.getY(0) + event.getY(1)) / 2);
}
}
布局xml:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/reposition_test_layout"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<ImageView
android:id="@+id/android"
android:src="@drawable/android"
android:layout_width="300dp"
android:layout_height="300dp"
android:scaleType="matrix"
android:contentDescription="@string/android_description" >
</ImageView>
</LinearLayout>
答案 0 :(得分:10)
将以下参数添加到Touch
类:
private float dx; // postTranslate X distance
private float dy; // postTranslate Y distance
private float[] matrixValues = new float[9];
float matrixX = 0; // X coordinate of matrix inside the ImageView
float matrixY = 0; // Y coordinate of matrix inside the ImageView
float width = 0; // width of drawable
float height = 0; // height of drawable
在case MotionEvent.ACTION_MOVE:
if (mode == DRAG) {
matrix.set(savedMatrix);
matrix.getValues(matrixValues);
matrixX = matrixValues[2];
matrixY = matrixValues[5];
width = matrixValues[0] * (((ImageView) view).getDrawable()
.getIntrinsicWidth());
height = matrixValues[4] * (((ImageView) view).getDrawable()
.getIntrinsicHeight());
dx = event.getX() - start.x;
dy = event.getY() - start.y;
//if image will go outside left bound
if (matrixX + dx < 0){
dx = -matrixX;
}
//if image will go outside right bound
if(matrixX + dx + width > view.getWidth()){
dx = view.getWidth() - matrixX - width;
}
//if image will go oustside top bound
if (matrixY + dy < 0){
dy = -matrixY;
}
//if image will go outside bottom bound
if(matrixY + dy + height > view.getHeight()){
dy = view.getHeight() - matrixY - height;
}
matrix.postTranslate(dx, dy);
}
答案 1 :(得分:1)
Android文档说:
可以通过调用来检索视图的位置 方法 getLeft()和 getTop()。前者返回左边,或者X, 表示视图的矩形的坐标。后者回归 表示视图的矩形的顶部或Y坐标。 这些方法都返回视图相对于它的位置 的父即可。
此外,还提供了几种便捷方法 避免不必要的计算,即 getRight()和 getBottom()。 这些方法返回右边和底边的坐标 表示视图的矩形。例如,调用getRight() 类似于以下计算:getLeft()+ getWidth()。
因此,您可以在移动之前获取图像坐标,并且可以在 OnTouchListener 类中计算移动的度量。如果( X coordinate of your image plus horizontal movement that you computed,be greater than device width
或< em> Y coordinate of your image plus vertical movement that you computed,be greater than device height
)您的图片无法移动。
答案 2 :(得分:1)
我使用了Benito Bertoli的答案并修改了ACTION_MOVE代码,修改了次要和主要标志,使图像缩放和拖动图像缩放
这是代码
private static final float MIN_ZOOM = 1f;
private static final float MAX_ZOOM = 2.5f;
public boolean onTouch(View v, MotionEvent event) {
ImageView view = (ImageView) v;
view.setScaleType(ImageView.ScaleType.MATRIX);
// Handle touch events here...
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN: //first finger down only
savedMatrix.set(matrix);
start.set(event.getX(), event.getY());
Log.d(TAG, "mode=DRAG" );
mode = DRAG;
break;
case MotionEvent.ACTION_UP: //first finger lifted
case MotionEvent.ACTION_POINTER_UP: //second finger lifted
mode = NONE;
Log.d(TAG, "mode=NONE" );
break;
case MotionEvent.ACTION_POINTER_DOWN: //second finger 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);
//matrix.postTranslate(event.getX() - start.x, event.getY() - start.y);
matrix.set(savedMatrix);
matrix.getValues(matrixValues);
matrixX = matrixValues[2];
matrixY = matrixValues[5];
width = matrixValues[0] * (view.getDrawable().getIntrinsicWidth());
height = matrixValues[4] * (view.getDrawable().getIntrinsicHeight());
dx = event.getX() - start.x;
dy = event.getY() - start.y;
//if image will go outside left bound
if (matrixX + dx > 0){
Log.e("dx","lef bound " + dx);
dx = -matrixX;
}
//if image will go outside right bound
if(matrixX + dx + width < view.getWidth()){
dx = view.getWidth() - matrixX - width;
}
//if image will go oustside top bound
if (matrixY + dy > 0){
dy = -matrixY;
}
//if image will go outside bottom bound
if(matrixY + dy + height < view.getHeight()){
dy = view.getHeight() - matrixY - height;
}
matrix.postTranslate(dx, dy);
}
else if (mode == ZOOM) {
Float newDist = spacing(event);
Log.d(TAG, "newDist=" + newDist);
if (newDist > 10f) {
matrix.set(savedMatrix);
float scale = newDist / oldDist;
float[] values = new float[9];
matrix.getValues(values);
float currentScale = values[Matrix.MSCALE_X];
if(scale * currentScale > MAX_ZOOM)
scale = MAX_ZOOM / currentScale;
else if (scale * currentScale < MIN_ZOOM)
scale = MIN_ZOOM / currentScale;
matrix.postScale(scale, scale, mid.x, mid.y);
}
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 (float)Math.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);
}
return drawable;
}
答案 3 :(得分:1)
我们需要根据视图坐标创建两个Rect对象,一个用于我们的视图,另一个用于我们的图像。
float[] values = new float[9];
matrix.getValues(values);
float globalX = values[Matrix.MTRANS_X];
float globalY = values[Matrix.MTRANS_Y];
float scaleX = values[Matrix.MSCALE_X];
float scaleY = values[Matrix.MSCALE_Y];
Rect viewRect = new Rect(0, 0, viewWidth, viewHeight);
Rect imageRect = new Rect((int) globalX, (int) globalY, Math.round(bitmapWidth * scaleX + globalX),
Math.round(bitmapHeight * scaleY + globalY));
如果我们希望我们的图片始终在我们的视图中,那么我们检查一下:
if (!viewRect.contains(imageRect)) {
matrix.set(lastSetMatrix); //return to last saved parameters
}
有时我们需要我们的图像总是比我们的视图大,以便在视图中定位图像的一部分,然后我们可以检查:
if (!imageRect.contains(viewRect)) {
matrix.set(lastSetMatrix);
}
答案 4 :(得分:0)
我已经完成了这段代码。当我放大母鸡它不应该超出界限。它的工作正常。但是当它触及x = 0和y = 0的坐标时,它不会最小化。
int FLAG=0;
else if (mode == ZOOM) {
float newDistance = spacing(event);
Log.i("new distance ", newDistance+"");
matrix.getValues(matrixValues);
matrixX = matrixValues[2];
matrixY = matrixValues[5];
width = matrixValues[0]
* (((ImageView) view).getDrawable().getIntrinsicWidth());
height = matrixValues[4]
* (((ImageView) view).getDrawable()
.getIntrinsicHeight());
dx = event.getX() - start.x;
dy = event.getY() - start.y;
// if image will go outside left bound
if (matrixX + dx < 0) {
FLAG=1;
}
if (matrixX + dx + width > view.getWidth()) {
FLAG=1;
//dx = view.getWidth() - matrixX - width;
}
// if image will go oustside top bound
if (matrixY + dy < 0) {
FLAG=1;
//dy = -matrixY;
}
// if image will go outside bottom bound
if (matrixY + dy + height > view.getHeight()) {
FLAG=1;
//dy = view.getHeight() - matrixY - height;
}
if (matrixX + dx ==0 || matrixY + dy==0){
FLAG=0;
}
if (newDistance > 10f && FLAG==0) {
matrix.set(savedMatrix);
float scale = newDistance / oldDistance;
float[] values = new float[9];
matrix.getValues(values);
float currentScale = values[Matrix.MSCALE_X];
if (scale * currentScale > MAX_ZOOM)
scale = MAX_ZOOM / currentScale;
else if (scale * currentScale < MIN_ZOOM)
scale = MIN_ZOOM / currentScale;
matrix.postScale(scale, scale, mid.x, mid.y);
}
}
break;