English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Реализация масштабирования и перетаскивания изображений с помощью пользовательского контрола ImageView в Android

Обзор: С помощью пользовательского компонента ImageView, вызываемого в xml-разметке, можно масштабировать изображения.

/**
* Управление ImageView на основе пользовательских функций, поддерживающее многоточечное масштабирование и перетаскивание изображений
* 
* @author qiuwanyong
*/
public class MyImageView extends ImageView {
/**
* Константа состояния инициализации
*/
public static final int STATUS_INIT = 1;
/**
* Константа состояния увеличения изображения
*/
public static final int STATUS_ZOOM_OUT = 2;
/**
* Константа состояния уменьшения изображения
*/
public static final int STATUS_ZOOM_IN = 3;
/**
* Константа состояния перетаскивания изображения
*/
public static final int STATUS_MOVE = 4;
/**
* Мatrix для перемещения и масштабирования изображения
*/
private Matrix matrix = new Matrix();
/**
* Bitmap объект для отображения
*/
private Bitmap sourceBitmap;
/**
* Запись текущего состояния операции, возможные значения: STATUS_INIT, STATUS_ZOOM_OUT, STATUS_ZOOM_IN и STATUS_MOVE
*/
private int currentStatus;
/**
* Ширина контроллера ZoomImageView
*/
private int width;
/**
* Высота контроллера ZoomImageView
*/
private int height;
/**
* Запись координаты X центральной точки при одновременном放置 двух пальцев на экране
*/
private float centerPointX;
/**
* Запись координаты Y центральной точки при одновременном放置 двух пальцев на экране
*/
private float centerPointY;
/**
* Запись текущей ширины изображения, при масштабировании изображения этот параметр изменяется
*/
private float currentBitmapWidth;
/**
* Запись текущей высоты изображения, при масштабировании изображения этот параметр изменяется
*/
private float currentBitmapHeight;
/**
* Запись координаты X последнего перемещения пальца
*/
private float lastXMove = -1;
/**
* Запись координаты Y последнего перемещения пальца
*/
private float lastYMove = -1;
/**
* Запись расстояния перемещения пальца по горизонтали
*/
private float movedDistanceX;
/**
* Запись расстояния перемещения пальца по вертикальной координате
*/
private float movedDistanceY;
/**
* Записывает горизонтальное смещение изображения в матрице
*/
private float totalTranslateX;
/**
* Записывает вертикальное смещение изображения в матрице
*/
private float totalTranslateY;
/**
* Записывает общее масштабирование изображения в матрице
*/
private float totalRatio;
/**
* Записывает масштаб, вызванный перемещением пальцев
*/
private float scaledRatio;
/**
* Записывает масштаб изображения при его инициализации
*/
private float initRatio;
/**
* Записывает上次 расстояние между двумя пальцами
*/
private double lastFingerDis;
/**
* Конструктор ZoomImageView, устанавливает текущий статус на STATUS_INIT.
* 
* @param context
* @param attrs
*/
public MyImageView(Context context, AttributeSet attrs) {
super(context, attrs);
currentStatus = STATUS_INIT;
}
/**
* Установите изображение для отображения.
* 
* @param bitmap
* Bitmap объект для отображения
*/
public void setImageBitmap(Bitmap bitmap) {
sourceBitmap = bitmap;
invalidate();
}
@Override
protected void onLayout(boolean changed, int left, int top, int right,
int bottom) {
super.onLayout(changed, left, top, right, bottom);
if (changed) {
// Отдельно получаем ширину и высоту ZoomImageView
width = getWidth();
height = getHeight();
}
}
@SuppressLint("NewApi") @Override
public boolean onTouchEvent(MotionEvent event) {
if (initRatio == totalRatio) {
getParent().requestDisallowInterceptTouchEvent(false);
} else {
getParent().requestDisallowInterceptTouchEvent(true);
}
switch (event.getActionMasked()) {
case MotionEvent.ACTION_POINTER_DOWN:
if (event.getPointerCount() == 2) {
// При нажатии двух пальцев на экран, вычисляется расстояние между пальцами
lastFingerDis = distanceBetweenFingers(event);
}
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_MOVE:
if (event.getPointerCount() == 1) {
// Только при движении одного пальца по экрану, это состояние перетаскивания
float xMove = event.getX();
float yMove = event.getY();
if (lastXMove == -1 && lastYMove == -1) {
lastXMove = xMove;
lastYMove = yMove;
}
currentStatus = STATUS_MOVE;
movedDistanceX = xMove - lastXMove;
movedDistanceY = yMove - lastYMove;
// Выполнение проверки границ, не разрешается вывести изображение за пределы границ
if (totalTranslateX + movedDistanceX > 0) {
movedDistanceX = 0;
} else if (width - (totalTranslateX + movedDistanceX) > currentBitmapWidth) {
movedDistanceX = 0;
}
if (totalTranslateY + movedDistanceY > 0) {
movedDistanceY = 0;
} else if (height - (totalTranslateY + movedDistanceY) > currentBitmapHeight) {
movedDistanceY = 0;
}
// Вызов метода onDraw() для рисования изображения
invalidate();
lastXMove = xMove;
lastYMove = yMove;
} else if (event.getPointerCount() == 2) {
// У двух пальцев нажимается на экран и перемещается, это состояние масштабирования
centerPointBetweenFingers(event);
if (fingerDis > lastFingerDis) {
currentStatus = STATUS_ZOOM_OUT;
currentStatus = STATUS_ZOOM_IN;
} else {
// Проверка коэффициента масштабирования, максимальное увеличение изображения до 4 раз, минимальное уменьшение до начального коэффициента
}
if ((currentStatus == STATUS_ZOOM_OUT && totalRatio < 4 * initRatio)
|| (currentStatus == STATUS_ZOOM_IN && totalRatio > initRatio)) {
scaledRatio = (float) (fingerDis / lastFingerDis);
totalRatio = totalRatio * scaledRatio;
if (totalRatio > 4 * initRatio) {
totalRatio = 4 * initRatio;
else if (totalRatio < initRatio) {
}
totalRatio = initRatio;
}
// Вызов метода onDraw() для рисования изображения
invalidate();
lastFingerDis = fingerDis;
}
}
break;
case MotionEvent.ACTION_POINTER_UP:
if (event.getPointerCount() == 2) {
// Возвращение временных значений к начальным при выходе пальца за пределы экрана
lastXMove = -1;
lastYMove = -1;
}
break;
case MotionEvent.ACTION_UP:
// Возвращение временных значений к начальным при выходе пальца за пределы экрана
lastXMove = -1;
lastYMove = -1;
break;
default:
break;
}
return true;
}
/**
* В зависимости от значения currentStatus выполняется определенная операция рисования изображения.
*/
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
switch (currentStatus) {
case STATUS_ZOOM_OUT:
case STATUS_ZOOM_IN:
zoom(canvas);
break;
case STATUS_MOVE:
move(canvas);
break;
case STATUS_INIT:
initBitmap(canvas);
default:
if (sourceBitmap != null) {
canvas.drawBitmap(sourceBitmap, matrix, null);
}
break;
}
}
/**
* Обработать изображение масштабирования.
* 
* @param canvas
*/
private void zoom(Canvas canvas) {
matrix.reset();
// Масштабировать изображение по общей масштабирующей пропорции
matrix.postScale(totalRatio, totalRatio);
float scaledWidth = sourceBitmap.getWidth() * totalRatio;
float scaledHeight = sourceBitmap.getHeight() * totalRatio;
float translateX = 0f;
float translateY = 0f;
// Если текущая ширина изображения меньше ширины экрана, то масштабировать изображение по горизонтали по координате центра экрана. В противном случае, по координате центра两点.
if (currentBitmapWidth < width) {
translateX = (width - scaledWidth) / 2f;
} else {
translateX = totalTranslateX * scaledRatio + centerPointX
* (1 - scaledRatio);
// Выполнить проверку границ, чтобы после масштабирования изображения оно не сместилось за экран в горизонтальном направлении
if (translateX > 0) {
translateX = 0;
} else if (width - translateX > scaledWidth) {
translateX = width - scaledWidth;
}
}
// Если текущая высота изображения меньше высоты экрана, то масштабировать изображение по вертикали по координате центра экрана. В противном случае, по координате центра两点.
if (currentBitmapHeight < height) {
translateY = (height - scaledHeight) / 2f;
} else {
translateY = totalTranslateY * scaledRatio + centerPointY
* (1 - scaledRatio);
// Выполнить проверку границ, чтобы после масштабирования изображения оно не сместилось за экран в вертикальном направлении
if (translateY > 0) {
translateY = 0;
else if (height - translateY > scaledHeight) {
translateY = height - scaledHeight;
}
}
// После масштабирования изображение смещается, чтобы сохранить центральное положение
matrix.postTranslate(translateX, translateY);
totalTranslateX = translateX;
totalTranslateY = translateY;
currentBitmapWidth = scaledWidth;
currentBitmapHeight = scaledHeight;
canvas.drawBitmap(sourceBitmap, matrix, null);
}
/**
* Выполняет трансляцию изображения
* 
* @param canvas
*/
private void move(Canvas canvas) {
matrix.reset();
// Вычисляется общее смещение в зависимости от расстояния перемещения пальца
float translateX = totalTranslateX + movedDistanceX;
float translateY = totalTranslateY + movedDistanceY;
// Сначала изображение масштабируется по уже существующему коэффициенту масштабирования
matrix.postScale(totalRatio, totalRatio);
// Затем выполняется смещение в зависимости от расстояния перемещения
matrix.postTranslate(translateX, translateY);
totalTranslateX = translateX;
totalTranslateY = translateY;
canvas.drawBitmap(sourceBitmap, matrix, null);
}
/**
* Включает инициализацию изображения, включая выравнивание изображения по центру и его уменьшение пропорционально, если оно больше экрана
* 
* @param canvas
*/
private void initBitmap(Canvas canvas) {
if (sourceBitmap != null) {
matrix.reset();
int bitmapWidth = sourceBitmap.getWidth();
int bitmapHeight = sourceBitmap.getHeight();
if (bitmapWidth > width || bitmapHeight > height) {
if (bitmapWidth - width > bitmapHeight - height) {
// Если ширина изображения больше ширины экрана, то изображение уменьшается пропорционально, чтобы его можно было полностью показать
float ratio = width / (bitmapWidth * 1.0f);
matrix.postScale(ratio, ratio);
float translateY = (height - (bitmapHeight * ratio)) / 2f;
// В направлении координаты Y выполняется смещение, чтобы обеспечить выравнивание изображения по центру
matrix.postTranslate(0, translateY);
totalTranslateY = translateY;
totalRatio = initRatio = ratio;
} else {
// Если высота изображения больше высоты экрана, то изображение уменьшается пропорционально, чтобы его можно было полностью показать
float ratio = height / (bitmapHeight * 1.0f);
matrix.postScale(ratio, ratio);
float translateX = (width - (bitmapWidth * ratio)) / 2f;
// Проводится смещение по горизонтали, чтобы изображение выровнялось по центру
matrix.postTranslate(translateX, 0);
totalTranslateX = translateX;
totalRatio = initRatio = ratio;
}
currentBitmapWidth = bitmapWidth * initRatio;
currentBitmapHeight = bitmapHeight * initRatio;
} else {
// Когда ширина и высота изображения меньше ширины и высоты экрана, изображение выравнивается по центру
float translateX = (width - sourceBitmap.getWidth()) / 2f;
float translateY = (height - sourceBitmap.getHeight()) / 2f;
matrix.postTranslate(translateX, translateY);
totalTranslateX = translateX;
totalTranslateY = translateY;
totalRatio = initRatio = 1f;
currentBitmapWidth = bitmapWidth;
currentBitmapHeight = bitmapHeight;
}
canvas.drawBitmap(sourceBitmap, matrix, null);
}
}
/**
* Рассчитывает расстояние между двумя пальцами.
* 
* @param event
* @return Расстояние между двумя пальцами
*/
@SuppressLint("NewApi") private double distanceBetweenFingers(MotionEvent event) {
float disX = Math.abs(event.getX(0) - event.getX(1));
float disY = Math.abs(event.getY(0) - event.getY(1));
return Math.sqrt(disX * disX + disY * disY);
}
/**
* Вычислить координаты центра между двумя пальцами.
* 
* @param event
*/
@SuppressLint("NewApi") private void centerPointBetweenFingers(MotionEvent event) {
float xPoint0 = event.getX(0);
float yPoint0 = event.getY(0);
float xPoint1 = event.getX(1);
float yPoint1 = event.getY(1);
centerPointX = (xPoint0 + xPoint1) / 2;
centerPointY = (yPoint0 + yPoint1) / 2;
}
}

Вызов в макете

Приведенный выше код для реализации масштабирования и拖ания изображения через пользовательский控件 ImageView для Android, представлен редактором. Надеюсь, это поможет вам. Если у вас есть какие-либо вопросы, пожалуйста, оставьте комментарий, редактор ответит вам своевременно. В этом regard, мы также очень благодарны всем за поддержку сайта呐喊 учебник!

Декларация: содержимое этой статьи взято из Интернета, авторские права принадлежат соответствующему автору. Контент был предоставлен пользователями Интернета, веб-сайт не имеет права собственности на него, не был отредактирован вручную и не несет ответственности за него. Если вы обнаружите материалы,涉嫌侵犯版权, пожалуйста, отправьте письмо по адресу: notice#oldtoolbag.com (во время отправки письма замените # на @),并提供相关证据. Если подтвердится, что материалы являются нарушающими авторские права, сайт немедленно удалят.

Тебе может понравиться