Ограничение Перетаскивания ImageView В Android
У меня есть ImageView в макете и установить OnTouchListener на ImageView, чтобы перетащить 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>
5 ответов
добавьте следующие параметры в 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);
}
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
или Y coordinate of your image plus vertical movement that you computed,be greater than device height
) ваше изображение не двигается.
я использовал ответ от Бенито Бертоли и изменил код 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;
}
-
нам нужно создать два объекта 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); }
-
Я сделал этот код. когда я приближаю курицу, она не должна выходить из границы. работает нормально.Но когда он касается кордината 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;