Android image Просмотреть увеличение и уменьшение масштаба
Привет, я новичок в приложении для Android. Я хочу увеличить и уменьшить масштаб ImageView. Я пробовал большую часть примера, но на всем этом изображении в режиме просмотра изображений есть увеличение и уменьшение масштаба. Я хочу увеличить и увеличить изображение. Уменьшение ImageView. Я хочу увеличить ширину и высоту просмотра изображения при увеличении и уменьшить ширину и высоту просмотра при уменьшении изображения. Кто-нибудь может мне предложить?
21 ответ
Сделайте два Java-класса
Зум класс
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.view.KeyEvent;
import android.view.View;
import android.widget.Button;
import android.widget.ImageButton;
public class Zoom extends View {
private Drawable image;
ImageButton img,img1;
private int zoomControler=20;
public Zoom(Context context){
super(context);
image=context.getResources().getDrawable(R.drawable.j);
//image=context.getResources().getDrawable(R.drawable.icon);
setFocusable(true);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//here u can control the width and height of the images........ this line is very important
image.setBounds((getWidth()/2)-zoomControler, (getHeight()/2)-zoomControler, (getWidth()/2)+zoomControler, (getHeight()/2)+zoomControler);
image.draw(canvas);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if(keyCode==KeyEvent.KEYCODE_DPAD_UP){
// zoom in
zoomControler+=10;
}
if(keyCode==KeyEvent.KEYCODE_DPAD_DOWN){
// zoom out
zoomControler-=10;
}
if(zoomControler<10){
zoomControler=10;
}
invalidate();
return true;
}
}
сделать второй класс
import android.app.Activity;
import android.os.Bundle;
public class Zoomexample extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(new Zoom(this));
}
}
Пожалуйста, следуйте приведенному ниже классу, который используется для увеличения и уменьшения масштаба для ImageView.
import android.app.Activity;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.ImageView;
public class ZoomInZoomOut extends Activity implements OnTouchListener
{
private static final String TAG = "Touch";
@SuppressWarnings("unused")
private static final float MIN_ZOOM = 1f,MAX_ZOOM = 1f;
// These matrices will be used to scale points of the image
Matrix matrix = new Matrix();
Matrix savedMatrix = new Matrix();
// The 3 states (events) which the user is trying to perform
static final int NONE = 0;
static final int DRAG = 1;
static final int ZOOM = 2;
int mode = NONE;
// these PointF objects are used to record the point(s) the user is touching
PointF start = new PointF();
PointF mid = new PointF();
float oldDist = 1f;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ImageView view = (ImageView) findViewById(R.id.imageView);
view.setOnTouchListener(this);
}
@Override
public boolean onTouch(View v, MotionEvent event)
{
ImageView view = (ImageView) v;
view.setScaleType(ImageView.ScaleType.MATRIX);
float scale;
dumpEvent(event);
// 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"); // write to LogCat
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: // first and second finger down
oldDist = spacing(event);
Log.d(TAG, "oldDist=" + oldDist);
if (oldDist > 5f) {
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); // create the transformation in the matrix of points
}
else if (mode == ZOOM)
{
// pinch zooming
float newDist = spacing(event);
Log.d(TAG, "newDist=" + newDist);
if (newDist > 5f)
{
matrix.set(savedMatrix);
scale = newDist / oldDist; // setting the scaling of the
// matrix...if scale > 1 means
// zoom in...if scale < 1 means
// zoom out
matrix.postScale(scale, scale, mid.x, mid.y);
}
}
break;
}
view.setImageMatrix(matrix); // display the transformation on screen
return true; // indicate event was handled
}
/*
* --------------------------------------------------------------------------
* Method: spacing Parameters: MotionEvent Returns: float Description:
* checks the spacing between the two fingers on touch
* ----------------------------------------------------
*/
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);
}
/*
* --------------------------------------------------------------------------
* Method: midPoint Parameters: PointF object, MotionEvent Returns: void
* Description: calculates the midpoint between the two fingers
* ------------------------------------------------------------
*/
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);
}
/** Show an event in the LogCat view, for debugging */
private void dumpEvent(MotionEvent event)
{
String names[] = { "DOWN", "UP", "MOVE", "CANCEL", "OUTSIDE","POINTER_DOWN", "POINTER_UP", "7?", "8?", "9?" };
StringBuilder sb = new StringBuilder();
int action = event.getAction();
int actionCode = action & MotionEvent.ACTION_MASK;
sb.append("event ACTION_").append(names[actionCode]);
if (actionCode == MotionEvent.ACTION_POINTER_DOWN || actionCode == MotionEvent.ACTION_POINTER_UP)
{
sb.append("(pid ").append(action >> MotionEvent.ACTION_POINTER_ID_SHIFT);
sb.append(")");
}
sb.append("[");
for (int i = 0; i < event.getPointerCount(); i++)
{
sb.append("#").append(i);
sb.append("(pid ").append(event.getPointerId(i));
sb.append(")=").append((int) event.getX(i));
sb.append(",").append((int) event.getY(i));
if (i + 1 < event.getPointerCount())
sb.append(";");
}
sb.append("]");
Log.d("Touch Events ---------", sb.toString());
}
}
Все остальные реализации здесь имеют какой-то недостаток. поэтому я в основном перепутал их и придумал это.
Создайте пользовательский вид как это:
ZoomableImageView.java:
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.widget.ImageView;
public class ZoomableImageView extends ImageView
{
Matrix matrix = new Matrix();
static final int NONE = 0;
static final int DRAG = 1;
static final int ZOOM = 2;
static final int CLICK = 3;
int mode = NONE;
PointF last = new PointF();
PointF start = new PointF();
float minScale = 1f;
float maxScale = 4f;
float[] m;
float redundantXSpace, redundantYSpace;
float width, height;
float saveScale = 1f;
float right, bottom, origWidth, origHeight, bmWidth, bmHeight;
ScaleGestureDetector mScaleDetector;
Context context;
public ZoomableImageView(Context context, AttributeSet attr)
{
super(context, attr);
super.setClickable(true);
this.context = context;
mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
matrix.setTranslate(1f, 1f);
m = new float[9];
setImageMatrix(matrix);
setScaleType(ScaleType.MATRIX);
setOnTouchListener(new OnTouchListener()
{
@Override
public boolean onTouch(View v, MotionEvent event)
{
mScaleDetector.onTouchEvent(event);
matrix.getValues(m);
float x = m[Matrix.MTRANS_X];
float y = m[Matrix.MTRANS_Y];
PointF curr = new PointF(event.getX(), event.getY());
switch (event.getAction())
{
//when one finger is touching
//set the mode to DRAG
case MotionEvent.ACTION_DOWN:
last.set(event.getX(), event.getY());
start.set(last);
mode = DRAG;
break;
//when two fingers are touching
//set the mode to ZOOM
case MotionEvent.ACTION_POINTER_DOWN:
last.set(event.getX(), event.getY());
start.set(last);
mode = ZOOM;
break;
//when a finger moves
//If mode is applicable move image
case MotionEvent.ACTION_MOVE:
//if the mode is ZOOM or
//if the mode is DRAG and already zoomed
if (mode == ZOOM || (mode == DRAG && saveScale > minScale))
{
float deltaX = curr.x - last.x;// x difference
float deltaY = curr.y - last.y;// y difference
float scaleWidth = Math.round(origWidth * saveScale);// width after applying current scale
float scaleHeight = Math.round(origHeight * saveScale);// height after applying current scale
//if scaleWidth is smaller than the views width
//in other words if the image width fits in the view
//limit left and right movement
if (scaleWidth < width)
{
deltaX = 0;
if (y + deltaY > 0)
deltaY = -y;
else if (y + deltaY < -bottom)
deltaY = -(y + bottom);
}
//if scaleHeight is smaller than the views height
//in other words if the image height fits in the view
//limit up and down movement
else if (scaleHeight < height)
{
deltaY = 0;
if (x + deltaX > 0)
deltaX = -x;
else if (x + deltaX < -right)
deltaX = -(x + right);
}
//if the image doesnt fit in the width or height
//limit both up and down and left and right
else
{
if (x + deltaX > 0)
deltaX = -x;
else if (x + deltaX < -right)
deltaX = -(x + right);
if (y + deltaY > 0)
deltaY = -y;
else if (y + deltaY < -bottom)
deltaY = -(y + bottom);
}
//move the image with the matrix
matrix.postTranslate(deltaX, deltaY);
//set the last touch location to the current
last.set(curr.x, curr.y);
}
break;
//first finger is lifted
case MotionEvent.ACTION_UP:
mode = NONE;
int xDiff = (int) Math.abs(curr.x - start.x);
int yDiff = (int) Math.abs(curr.y - start.y);
if (xDiff < CLICK && yDiff < CLICK)
performClick();
break;
// second finger is lifted
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
break;
}
setImageMatrix(matrix);
invalidate();
return true;
}
});
}
@Override
public void setImageBitmap(Bitmap bm)
{
super.setImageBitmap(bm);
bmWidth = bm.getWidth();
bmHeight = bm.getHeight();
}
public void setMaxZoom(float x)
{
maxScale = x;
}
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener
{
@Override
public boolean onScaleBegin(ScaleGestureDetector detector)
{
mode = ZOOM;
return true;
}
@Override
public boolean onScale(ScaleGestureDetector detector)
{
float mScaleFactor = detector.getScaleFactor();
float origScale = saveScale;
saveScale *= mScaleFactor;
if (saveScale > maxScale)
{
saveScale = maxScale;
mScaleFactor = maxScale / origScale;
}
else if (saveScale < minScale)
{
saveScale = minScale;
mScaleFactor = minScale / origScale;
}
right = width * saveScale - width - (2 * redundantXSpace * saveScale);
bottom = height * saveScale - height - (2 * redundantYSpace * saveScale);
if (origWidth * saveScale <= width || origHeight * saveScale <= height)
{
matrix.postScale(mScaleFactor, mScaleFactor, width / 2, height / 2);
if (mScaleFactor < 1)
{
matrix.getValues(m);
float x = m[Matrix.MTRANS_X];
float y = m[Matrix.MTRANS_Y];
if (mScaleFactor < 1)
{
if (Math.round(origWidth * saveScale) < width)
{
if (y < -bottom)
matrix.postTranslate(0, -(y + bottom));
else if (y > 0)
matrix.postTranslate(0, -y);
}
else
{
if (x < -right)
matrix.postTranslate(-(x + right), 0);
else if (x > 0)
matrix.postTranslate(-x, 0);
}
}
}
}
else
{
matrix.postScale(mScaleFactor, mScaleFactor, detector.getFocusX(), detector.getFocusY());
matrix.getValues(m);
float x = m[Matrix.MTRANS_X];
float y = m[Matrix.MTRANS_Y];
if (mScaleFactor < 1) {
if (x < -right)
matrix.postTranslate(-(x + right), 0);
else if (x > 0)
matrix.postTranslate(-x, 0);
if (y < -bottom)
matrix.postTranslate(0, -(y + bottom));
else if (y > 0)
matrix.postTranslate(0, -y);
}
}
return true;
}
}
@Override
protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec)
{
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
width = MeasureSpec.getSize(widthMeasureSpec);
height = MeasureSpec.getSize(heightMeasureSpec);
//Fit to screen.
float scale;
float scaleX = width / bmWidth;
float scaleY = height / bmHeight;
scale = Math.min(scaleX, scaleY);
matrix.setScale(scale, scale);
setImageMatrix(matrix);
saveScale = 1f;
// Center the image
redundantYSpace = height - (scale * bmHeight) ;
redundantXSpace = width - (scale * bmWidth);
redundantYSpace /= 2;
redundantXSpace /= 2;
matrix.postTranslate(redundantXSpace, redundantYSpace);
origWidth = width - 2 * redundantXSpace;
origHeight = height - 2 * redundantYSpace;
right = width * saveScale - width - (2 * redundantXSpace * saveScale);
bottom = height * saveScale - height - (2 * redundantYSpace * saveScale);
setImageMatrix(matrix);
}
}
Затем добавьте изображение так:
ZoomableImageView touch = (ZoomableImageView)findViewById(R.id.IMAGEID);
touch.setImageBitmap(bitmap);
Добавьте представление как это в XML:
<PACKAGE.ZoomableImageView
android:id="@+id/IMAGEID"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
Простой способ:
PhotoViewAttacher pAttacher;
pAttacher = new PhotoViewAttacher(Your_Image_View);
pAttacher.update();
Добавить ниже строку в build.gradle
:
compile 'com.commit451:PhotoView:1.2.4'
Я улучшил ответ, полученный из стека, для безупречного ZOOM (два пальца) / ROTATION (два пальца) / DRAG (один палец).
// ============================ XML-код ==================
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.flochat.imageviewzoomforstack.MainActivity">
<ImageView
android:id="@+id/imageview_trash"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/trash" />
</LinearLayout>
// ============================ Java-код ================== ========
public class MainActivity extends AppCompatActivity {
ImageView photoview2;
float[] lastEvent = null;
float d = 0f;
float newRot = 0f;
private boolean isZoomAndRotate;
private boolean isOutSide;
private static final int NONE = 0;
private static final int DRAG = 1;
private static final int ZOOM = 2;
private int mode = NONE;
private PointF start = new PointF();
private PointF mid = new PointF();
float oldDist = 1f;
private float xCoOrdinate, yCoOrdinate;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_main);
photoview2 = findViewById(R.id.imageview_trash);
photoview2.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
ImageView view = (ImageView) v;
view.bringToFront();
viewTransformation(view, event);
return true;
}
});
}
private void viewTransformation(View view, MotionEvent event) {
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
xCoOrdinate = view.getX() - event.getRawX();
yCoOrdinate = view.getY() - event.getRawY();
start.set(event.getX(), event.getY());
isOutSide = false;
mode = DRAG;
lastEvent = null;
break;
case MotionEvent.ACTION_POINTER_DOWN:
oldDist = spacing(event);
if (oldDist > 10f) {
midPoint(mid, event);
mode = ZOOM;
}
lastEvent = new float[4];
lastEvent[0] = event.getX(0);
lastEvent[1] = event.getX(1);
lastEvent[2] = event.getY(0);
lastEvent[3] = event.getY(1);
d = rotation(event);
break;
case MotionEvent.ACTION_UP:
isZoomAndRotate = false;
if (mode == DRAG) {
float x = event.getX();
float y = event.getY();
}
case MotionEvent.ACTION_OUTSIDE:
isOutSide = true;
mode = NONE;
lastEvent = null;
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
lastEvent = null;
break;
case MotionEvent.ACTION_MOVE:
if (!isOutSide) {
if (mode == DRAG) {
isZoomAndRotate = false;
view.animate().x(event.getRawX() + xCoOrdinate).y(event.getRawY() + yCoOrdinate).setDuration(0).start();
}
if (mode == ZOOM && event.getPointerCount() == 2) {
float newDist1 = spacing(event);
if (newDist1 > 10f) {
float scale = newDist1 / oldDist * view.getScaleX();
view.setScaleX(scale);
view.setScaleY(scale);
}
if (lastEvent != null) {
newRot = rotation(event);
view.setRotation((float) (view.getRotation() + (newRot - d)));
}
}
}
break;
}
}
private float rotation(MotionEvent event) {
double delta_x = (event.getX(0) - event.getX(1));
double delta_y = (event.getY(0) - event.getY(1));
double radians = Math.atan2(delta_y, delta_x);
return (float) Math.toDegrees(radians);
}
private float spacing(MotionEvent event) {
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return (int) 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);
}
}
// ======================== Просто передайте любой вид, который вы хотите увеличить / повернуть / перетащить в метод viewTransformation(). Очень применимо для увеличения масштаба текста. Это не будет точечный текст.
Это старо, но это может помочь кому-то еще.
Ниже класс TouchImageView поддерживает как увеличение / уменьшение масштаба при нажатии или двойном нажатии
import android.content.Context;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.widget.ImageView;
public class TouchImageView extends ImageView implements GestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener {
Matrix matrix;
// 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;
// Remember some things for zooming
PointF last = new PointF();
PointF start = new PointF();
float minScale = 1f;
float maxScale = 3f;
float[] m;
int viewWidth, viewHeight;
static final int CLICK = 3;
float saveScale = 1f;
protected float origWidth, origHeight;
int oldMeasuredWidth, oldMeasuredHeight;
ScaleGestureDetector mScaleDetector;
Context context;
public TouchImageView(Context context) {
super(context);
sharedConstructing(context);
}
public TouchImageView(Context context, AttributeSet attrs) {
super(context, attrs);
sharedConstructing(context);
}
GestureDetector mGestureDetector;
private void sharedConstructing(Context context) {
super.setClickable(true);
this.context = context;
mGestureDetector = new GestureDetector(context, this);
mGestureDetector.setOnDoubleTapListener(this);
mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
matrix = new Matrix();
m = new float[9];
setImageMatrix(matrix);
setScaleType(ScaleType.MATRIX);
setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
mScaleDetector.onTouchEvent(event);
mGestureDetector.onTouchEvent(event);
PointF curr = new PointF(event.getX(), event.getY());
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
last.set(curr);
start.set(last);
mode = DRAG;
break;
case MotionEvent.ACTION_MOVE:
if (mode == DRAG) {
float deltaX = curr.x - last.x;
float deltaY = curr.y - last.y;
float fixTransX = getFixDragTrans(deltaX, viewWidth,
origWidth * saveScale);
float fixTransY = getFixDragTrans(deltaY, viewHeight,
origHeight * saveScale);
matrix.postTranslate(fixTransX, fixTransY);
fixTrans();
last.set(curr.x, curr.y);
}
break;
case MotionEvent.ACTION_UP:
mode = NONE;
int xDiff = (int) Math.abs(curr.x - start.x);
int yDiff = (int) Math.abs(curr.y - start.y);
if (xDiff < CLICK && yDiff < CLICK)
performClick();
break;
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
break;
}
setImageMatrix(matrix);
invalidate();
return true; // indicate event was handled
}
});
}
public void setMaxZoom(float x) {
maxScale = x;
}
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
return false;
}
@Override
public boolean onDoubleTap(MotionEvent e) {
// Double tap is detected
Log.i("MAIN_TAG", "Double tap detected");
float origScale = saveScale;
float mScaleFactor;
if (saveScale == maxScale) {
saveScale = minScale;
mScaleFactor = minScale / origScale;
} else {
saveScale = maxScale;
mScaleFactor = maxScale / origScale;
}
matrix.postScale(mScaleFactor, mScaleFactor, viewWidth / 2,
viewHeight / 2);
fixTrans();
return false;
}
@Override
public boolean onDoubleTapEvent(MotionEvent e) {
return false;
}
@Override
public boolean onDown(MotionEvent e) {
return false;
}
@Override
public void onShowPress(MotionEvent e) {
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
return false;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
return false;
}
@Override
public void onLongPress(MotionEvent e) {
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
return false;
}
private class ScaleListener extends
ScaleGestureDetector.SimpleOnScaleGestureListener {
@Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
mode = ZOOM;
return true;
}
@Override
public boolean onScale(ScaleGestureDetector detector) {
float mScaleFactor = detector.getScaleFactor();
float origScale = saveScale;
saveScale *= mScaleFactor;
if (saveScale > maxScale) {
saveScale = maxScale;
mScaleFactor = maxScale / origScale;
} else if (saveScale < minScale) {
saveScale = minScale;
mScaleFactor = minScale / origScale;
}
if (origWidth * saveScale <= viewWidth
|| origHeight * saveScale <= viewHeight)
matrix.postScale(mScaleFactor, mScaleFactor, viewWidth / 2,
viewHeight / 2);
else
matrix.postScale(mScaleFactor, mScaleFactor,
detector.getFocusX(), detector.getFocusY());
fixTrans();
return true;
}
}
void fixTrans() {
matrix.getValues(m);
float transX = m[Matrix.MTRANS_X];
float transY = m[Matrix.MTRANS_Y];
float fixTransX = getFixTrans(transX, viewWidth, origWidth * saveScale);
float fixTransY = getFixTrans(transY, viewHeight, origHeight
* saveScale);
if (fixTransX != 0 || fixTransY != 0)
matrix.postTranslate(fixTransX, fixTransY);
}
float getFixTrans(float trans, float viewSize, float contentSize) {
float minTrans, maxTrans;
if (contentSize <= viewSize) {
minTrans = 0;
maxTrans = viewSize - contentSize;
} else {
minTrans = viewSize - contentSize;
maxTrans = 0;
}
if (trans < minTrans)
return -trans + minTrans;
if (trans > maxTrans)
return -trans + maxTrans;
return 0;
}
float getFixDragTrans(float delta, float viewSize, float contentSize) {
if (contentSize <= viewSize) {
return 0;
}
return delta;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
viewWidth = MeasureSpec.getSize(widthMeasureSpec);
viewHeight = MeasureSpec.getSize(heightMeasureSpec);
//
// Rescales image on rotation
//
if (oldMeasuredHeight == viewWidth && oldMeasuredHeight == viewHeight
|| viewWidth == 0 || viewHeight == 0)
return;
oldMeasuredHeight = viewHeight;
oldMeasuredWidth = viewWidth;
if (saveScale == 1) {
// Fit to screen.
float scale;
Drawable drawable = getDrawable();
if (drawable == null || drawable.getIntrinsicWidth() == 0
|| drawable.getIntrinsicHeight() == 0)
return;
int bmWidth = drawable.getIntrinsicWidth();
int bmHeight = drawable.getIntrinsicHeight();
Log.d("bmSize", "bmWidth: " + bmWidth + " bmHeight : " + bmHeight);
float scaleX = (float) viewWidth / (float) bmWidth;
float scaleY = (float) viewHeight / (float) bmHeight;
scale = Math.min(scaleX, scaleY);
matrix.setScale(scale, scale);
// Center the image
float redundantYSpace = (float) viewHeight
- (scale * (float) bmHeight);
float redundantXSpace = (float) viewWidth
- (scale * (float) bmWidth);
redundantYSpace /= (float) 2;
redundantXSpace /= (float) 2;
matrix.postTranslate(redundantXSpace, redundantYSpace);
origWidth = viewWidth - 2 * redundantXSpace;
origHeight = viewHeight - 2 * redundantYSpace;
setImageMatrix(matrix);
}
fixTrans();
}
}
Использование: Вы можете заменить свой ImageView
с TouchImageView в XML и Java
1. Для XML
<?xml version="1.0" encoding="utf-8"?>
<com.example.android.myapp.TouchImageView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/imViewedImage"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true"
android:focusable="true" />
2. Для Java
TouchImageView imViewedImage = findViewById(R.id.imViewedImage);
Это еще одна реализация, основанная на коде, размещенном Николасом Тайлером.
Исправлены следующие ошибки:
- настройка
minScale
на номер меньше 1 сейчас работает - Вам не нужно использовать
setImageBitmap()
установить изображение (вы можете использовать, например,setImageResource()
- Все конструкторы теперь работают правильно
Следующие вещи, среди прочего, убраны:
OnTouchListener
не используется, это не нужно, потому что класс может просто реализоватьonTouchEvent()
метод.Назначение
right = width * saveScale - width - (2 * redundantXSpace * saveScale);
был упрощен доright = (originalBitmapWidth * saveScale) - width
Что, по моему выбору, гораздо менее запутанно.- Некоторые переменные-члены удалены (возможно, больше состояния можно удалить из этого класса)
Это не идеально, но здесь вы идете:
import android.content.Context;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.widget.ImageView;
/**
* Created by alex on 23/02/16.
* Based on code posted by Nicolas Tyler here:
* https://stackru.com/questions/6650398/android-imageview-zoom-in-and-zoom-out
*/
public class ZoomableImageView extends ImageView {
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
@Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
mode = ZOOM;
return true;
}
@Override
public boolean onScale(ScaleGestureDetector detector) {
float scaleFactor = detector.getScaleFactor();
float newScale = saveScale * scaleFactor;
if (newScale < maxScale && newScale > minScale) {
saveScale = newScale;
float width = getWidth();
float height = getHeight();
right = (originalBitmapWidth * saveScale) - width;
bottom = (originalBitmapHeight * saveScale) - height;
float scaledBitmapWidth = originalBitmapWidth * saveScale;
float scaledBitmapHeight = originalBitmapHeight * saveScale;
if (scaledBitmapWidth <= width || scaledBitmapHeight <= height) {
matrix.postScale(scaleFactor, scaleFactor, width / 2, height / 2);
} else {
matrix.postScale(scaleFactor, scaleFactor, detector.getFocusX(), detector.getFocusY());
}
}
return true;
}
}
static final int NONE = 0;
static final int DRAG = 1;
static final int ZOOM = 2;
static final int CLICK = 3;
private int mode = NONE;
private Matrix matrix = new Matrix();
private PointF last = new PointF();
private PointF start = new PointF();
private float minScale = 0.5f;
private float maxScale = 4f;
private float[] m;
private float redundantXSpace, redundantYSpace;
private float saveScale = 1f;
private float right, bottom, originalBitmapWidth, originalBitmapHeight;
private ScaleGestureDetector mScaleDetector;
public ZoomableImageView(Context context) {
super(context);
init(context);
}
public ZoomableImageView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public ZoomableImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context) {
super.setClickable(true);
mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
m = new float[9];
setImageMatrix(matrix);
setScaleType(ScaleType.MATRIX);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int bmHeight = getBmHeight();
int bmWidth = getBmWidth();
float width = getMeasuredWidth();
float height = getMeasuredHeight();
//Fit to screen.
float scale = width > height ? height / bmHeight : width / bmWidth;
matrix.setScale(scale, scale);
saveScale = 1f;
originalBitmapWidth = scale * bmWidth;
originalBitmapHeight = scale * bmHeight;
// Center the image
redundantYSpace = (height - originalBitmapHeight);
redundantXSpace = (width - originalBitmapWidth);
matrix.postTranslate(redundantXSpace / 2, redundantYSpace / 2);
setImageMatrix(matrix);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
mScaleDetector.onTouchEvent(event);
matrix.getValues(m);
float x = m[Matrix.MTRANS_X];
float y = m[Matrix.MTRANS_Y];
PointF curr = new PointF(event.getX(), event.getY());
switch (event.getAction()) {
//when one finger is touching
//set the mode to DRAG
case MotionEvent.ACTION_DOWN:
last.set(event.getX(), event.getY());
start.set(last);
mode = DRAG;
break;
//when two fingers are touching
//set the mode to ZOOM
case MotionEvent.ACTION_POINTER_DOWN:
last.set(event.getX(), event.getY());
start.set(last);
mode = ZOOM;
break;
//when a finger moves
//If mode is applicable move image
case MotionEvent.ACTION_MOVE:
//if the mode is ZOOM or
//if the mode is DRAG and already zoomed
if (mode == ZOOM || (mode == DRAG && saveScale > minScale)) {
float deltaX = curr.x - last.x;// x difference
float deltaY = curr.y - last.y;// y difference
float scaleWidth = Math.round(originalBitmapWidth * saveScale);// width after applying current scale
float scaleHeight = Math.round(originalBitmapHeight * saveScale);// height after applying current scale
boolean limitX = false;
boolean limitY = false;
//if scaleWidth is smaller than the views width
//in other words if the image width fits in the view
//limit left and right movement
if (scaleWidth < getWidth() && scaleHeight < getHeight()) {
// don't do anything
}
else if (scaleWidth < getWidth()) {
deltaX = 0;
limitY = true;
}
//if scaleHeight is smaller than the views height
//in other words if the image height fits in the view
//limit up and down movement
else if (scaleHeight < getHeight()) {
deltaY = 0;
limitX = true;
}
//if the image doesnt fit in the width or height
//limit both up and down and left and right
else {
limitX = true;
limitY = true;
}
if (limitY) {
if (y + deltaY > 0) {
deltaY = -y;
} else if (y + deltaY < -bottom) {
deltaY = -(y + bottom);
}
}
if (limitX) {
if (x + deltaX > 0) {
deltaX = -x;
} else if (x + deltaX < -right) {
deltaX = -(x + right);
}
}
//move the image with the matrix
matrix.postTranslate(deltaX, deltaY);
//set the last touch location to the current
last.set(curr.x, curr.y);
}
break;
//first finger is lifted
case MotionEvent.ACTION_UP:
mode = NONE;
int xDiff = (int) Math.abs(curr.x - start.x);
int yDiff = (int) Math.abs(curr.y - start.y);
if (xDiff < CLICK && yDiff < CLICK)
performClick();
break;
// second finger is lifted
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
break;
}
setImageMatrix(matrix);
invalidate();
return true;
}
public void setMaxZoom(float x) {
maxScale = x;
}
private int getBmWidth() {
Drawable drawable = getDrawable();
if (drawable != null) {
return drawable.getIntrinsicWidth();
}
return 0;
}
private int getBmHeight() {
Drawable drawable = getDrawable();
if (drawable != null) {
return drawable.getIntrinsicHeight();
}
return 0;
}
}
Я сделал свой собственный просмотр изображений с масштабированием. Для кода Chirag Raval нет ограничений / границ, поэтому пользователь может перетаскивать изображение с экрана.
Вот класс CustomImageView:
public class CustomImageVIew extends ImageView implements OnTouchListener {
private Matrix matrix = new Matrix();
private Matrix savedMatrix = new Matrix();
static final int NONE = 0;
static final int DRAG = 1;
static final int ZOOM = 2;
private int mode = NONE;
private PointF mStartPoint = new PointF();
private PointF mMiddlePoint = new PointF();
private Point mBitmapMiddlePoint = new Point();
private float oldDist = 1f;
private float matrixValues[] = {0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f};
private float scale;
private float oldEventX = 0;
private float oldEventY = 0;
private float oldStartPointX = 0;
private float oldStartPointY = 0;
private int mViewWidth = -1;
private int mViewHeight = -1;
private int mBitmapWidth = -1;
private int mBitmapHeight = -1;
private boolean mDraggable = false;
public CustomImageVIew(Context context) {
this(context, null, 0);
}
public CustomImageVIew(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomImageVIew(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.setOnTouchListener(this);
}
@Override
public void onSizeChanged (int w, int h, int oldw, int oldh){
super.onSizeChanged(w, h, oldw, oldh);
mViewWidth = w;
mViewHeight = h;
}
public void setBitmap(Bitmap bitmap){
if(bitmap != null){
setImageBitmap(bitmap);
mBitmapWidth = bitmap.getWidth();
mBitmapHeight = bitmap.getHeight();
mBitmapMiddlePoint.x = (mViewWidth / 2) - (mBitmapWidth / 2);
mBitmapMiddlePoint.y = (mViewHeight / 2) - (mBitmapHeight / 2);
matrix.postTranslate(mBitmapMiddlePoint.x, mBitmapMiddlePoint.y);
this.setImageMatrix(matrix);
}
}
@Override
public boolean onTouch(View v, MotionEvent event){
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
savedMatrix.set(matrix);
mStartPoint.set(event.getX(), event.getY());
mode = DRAG;
break;
case MotionEvent.ACTION_POINTER_DOWN:
oldDist = spacing(event);
if(oldDist > 10f){
savedMatrix.set(matrix);
midPoint(mMiddlePoint, event);
mode = ZOOM;
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
break;
case MotionEvent.ACTION_MOVE:
if(mode == DRAG){
drag(event);
} else if(mode == ZOOM){
zoom(event);
}
break;
}
return true;
}
public void drag(MotionEvent event){
matrix.getValues(matrixValues);
float left = matrixValues[2];
float top = matrixValues[5];
float bottom = (top + (matrixValues[0] * mBitmapHeight)) - mViewHeight;
float right = (left + (matrixValues[0] * mBitmapWidth)) -mViewWidth;
float eventX = event.getX();
float eventY = event.getY();
float spacingX = eventX - mStartPoint.x;
float spacingY = eventY - mStartPoint.y;
float newPositionLeft = (left < 0 ? spacingX : spacingX * -1) + left;
float newPositionRight = (spacingX) + right;
float newPositionTop = (top < 0 ? spacingY : spacingY * -1) + top;
float newPositionBottom = (spacingY) + bottom;
boolean x = true;
boolean y = true;
if(newPositionRight < 0.0f || newPositionLeft > 0.0f){
if(newPositionRight < 0.0f && newPositionLeft > 0.0f){
x = false;
} else{
eventX = oldEventX;
mStartPoint.x = oldStartPointX;
}
}
if(newPositionBottom < 0.0f || newPositionTop > 0.0f){
if(newPositionBottom < 0.0f && newPositionTop > 0.0f){
y = false;
} else{
eventY = oldEventY;
mStartPoint.y = oldStartPointY;
}
}
if(mDraggable){
matrix.set(savedMatrix);
matrix.postTranslate(x? eventX - mStartPoint.x : 0, y? eventY - mStartPoint.y : 0);
this.setImageMatrix(matrix);
if(x)oldEventX = eventX;
if(y)oldEventY = eventY;
if(x)oldStartPointX = mStartPoint.x;
if(y)oldStartPointY = mStartPoint.y;
}
}
public void zoom(MotionEvent event){
matrix.getValues(matrixValues);
float newDist = spacing(event);
float bitmapWidth = matrixValues[0] * mBitmapWidth;
float bimtapHeight = matrixValues[0] * mBitmapHeight;
boolean in = newDist > oldDist;
if(!in && matrixValues[0] < 1){
return;
}
if(bitmapWidth > mViewWidth || bimtapHeight > mViewHeight){
mDraggable = true;
} else{
mDraggable = false;
}
float midX = (mViewWidth / 2);
float midY = (mViewHeight / 2);
matrix.set(savedMatrix);
scale = newDist / oldDist;
matrix.postScale(scale, scale, bitmapWidth > mViewWidth ? mMiddlePoint.x : midX, bimtapHeight > mViewHeight ? mMiddlePoint.y : midY);
this.setImageMatrix(matrix);
}
/** Determine the space between the first two fingers */
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);
}
/** Calculate the mid point of the first two fingers */
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);
}
}
Вот как вы можете использовать его в своей деятельности:
CustomImageVIew mImageView = (CustomImageVIew)findViewById(R.id.customImageVIew1);
mImage.setBitmap(your bitmap);
И макет:
<your.package.name.CustomImageVIew
android:id="@+id/customImageVIew1"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_marginBottom="15dp"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:layout_marginTop="15dp"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:scaleType="matrix"/> // important
Вы должны поместить изображение в веб-просмотр и работать с этим. Элементы управления увеличением / уменьшением доступны в веб-представлении.
Я думаю, что ответ Чирага Равалса великолепен!
Единственное, что можно улучшить, это переместить весь этот код в некоторый класс, такой как:
PinchZoomImageView extends ImageView {...
и добавив туда начальную инициализацию Image Matrix, чтобы предотвратить масштабирование после первого касания:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
matrix = new Matrix(this.getImageMatrix());
}
Кстати, это исправит ошибку, упомянутую Мухаммедом Умаром и Базом
PS Наличие максимального и минимального пределов масштабирования также может быть полезным. Например, максимальное увеличение составляет 2X, а минимальное увеличение - это исходный масштаб, когда изображение помещается на экран:
static final int MAX_SCALE_FACTOR = 2;
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// Getting initial Image matrix
mViewMatrix = new Matrix(this.getImageMatrix());
mMinScaleMatrix = new Matrix(mViewMatrix);
float initialScale = getMatrixScale(mViewMatrix);
if (initialScale < 1.0f) // Image is bigger than screen
mMaxScale = MAX_SCALE_FACTOR;
else
mMaxScale = MAX_SCALE_FACTOR * initialScale;
mMinScale = getMatrixScale(mMinScaleMatrix);
}
@Override
public boolean onTouch(View v, MotionEvent event) {
ImageView view = (ImageView) v;
// We set scale only after onMeasure was called and automatically fit image to screen
if(!mWasScaleTypeSet) {
view.setScaleType(ImageView.ScaleType.MATRIX);
mWasScaleTypeSet = true;
}
float scale;
dumpEvent(event);
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN: // first finger down only
mCurSavedMatrix.set(mViewMatrix);
start.set(event.getX(), event.getY());
mCurrentMode = DRAG;
break;
case MotionEvent.ACTION_UP: // first finger lifted
case MotionEvent.ACTION_POINTER_UP: // second finger lifted
mCurrentMode = NONE;
float resScale = getMatrixScale(mViewMatrix);
if (resScale > mMaxScale) {
downscaleMatrix(resScale, mViewMatrix);
} else if (resScale < mMinScale)
mViewMatrix = new Matrix(mMinScaleMatrix);
else if ((resScale - mMinScale) < 0.1f) // Don't allow user to drag picture outside in case of FIT TO WINDOW zoom
mViewMatrix = new Matrix(mMinScaleMatrix);
else
break;
break;
case MotionEvent.ACTION_POINTER_DOWN: // first and second finger down
mOldDist = spacing(event);
Helper.LOGD(TAG, "oldDist=" + mOldDist);
if (mOldDist > 5f) {
mCurSavedMatrix.set(mViewMatrix);
midPoint(mCurMidPoint, event);
mCurrentMode = ZOOM;
Helper.LOGD(TAG, "mode=ZOOM");
}
break;
case MotionEvent.ACTION_MOVE:
if (mCurrentMode == DRAG) {
mViewMatrix.set(mCurSavedMatrix);
mViewMatrix.postTranslate(event.getX() - start.x, event.getY() - start.y); // create the transformation in the matrix of points
} else if (mCurrentMode == ZOOM) {
// pinch zooming
float newDist = spacing(event);
Helper.LOGD(TAG, "newDist=" + newDist);
if (newDist > 1.f) {
mViewMatrix.set(mCurSavedMatrix);
scale = newDist / mOldDist; // setting the scaling of the
// matrix...if scale > 1 means
// zoom in...if scale < 1 means
// zoom out
mViewMatrix.postScale(scale, scale, mCurMidPoint.x, mCurMidPoint.y);
}
}
break;
}
view.setImageMatrix(mViewMatrix); // display the transformation on screen
return true; // indicate event was handled
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////// PRIVATE SECTION ///////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// These matrices will be used to scale points of the image
private Matrix mViewMatrix = new Matrix();
private Matrix mCurSavedMatrix = new Matrix();
// These PointF objects are used to record the point(s) the user is touching
private PointF start = new PointF();
private PointF mCurMidPoint = new PointF();
private float mOldDist = 1f;
private Matrix mMinScaleMatrix;
private float mMinScale;
private float mMaxScale;
float[] mTmpValues = new float[9];
private boolean mWasScaleTypeSet;
/**
* Returns scale factor of the Matrix
* @param matrix
* @return
*/
private float getMatrixScale(Matrix matrix) {
matrix.getValues(mTmpValues);
return mTmpValues[Matrix.MSCALE_X];
}
/**
* Downscales matrix with the scale to maximum allowed scale factor, but the same translations
* @param scale
* @param dist
*/
private void downscaleMatrix(float scale, Matrix dist) {
float resScale = mMaxScale / scale;
dist.postScale(resScale, resScale, mCurMidPoint.x, mCurMidPoint.y);
}
Я получил самый полезный ответ от @Nicolas Tyler, но у меня были проблемы с тем, как работает синтаксис и логика. Я также не хотел никакого Альфа-пространства, и моя Алгебра была ржавой! Через 3 дня я собрал свою собственную версию этого.
Мой ответ отличается от @Nicolas Tyler следующим:
Различные имена переменных, которые я нашел, имеют больше смысла в базовых контекстных целях
Этот класс изображений Pinch-Zoom НЕ показывает альфа-пространство и позволит вам увеличивать и уменьшать масштаб, и все же не позволяет вам перетаскивать изображение под панорамирование и открывать альфа-пространство.
Добавлены глубокие комментарии к разделу матрицы, чтобы объяснить, что происходит с математикой
Этот класс изображения также позволит вам передать идентификатор ресурса и создаст из него растровое изображение
Гораздо более простые алгоритмы как для масштабирования, так и для перевода и нескольких переменных
Изменение изображения внутри этого приведет к его увеличению / уменьшению, так что новое изображение занимает контейнер просмотра
Отличное обновление ресурсов по алгебре можно найти здесь: https://youtu.be/IiXB6tYtY4w?t=4m12s Это видео охватывает ядро матриц скаляра и перевода (и поможет вам разобраться в материалах MTRANS_X и MTRANS_Y). Если у вас есть вопросы, я сделаю все возможное, чтобы ответить (но я не эксперт по алгебре).
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.widget.ImageView;
public class iImage extends ImageView
{
static final int NONE_MODE = 0;
static final int DRAG_MODE = 1;
static final int ZOOM_MODE = 2;
int _mode = NONE_MODE;
Matrix _matrix = new Matrix();
PointF _previousPoint = new PointF();
PointF _startPoint = new PointF();
float _currentScale = 1f;
float _minScale = 1f;
float _maxScale = 3f;
float[] _arrayOf9Floats;
float _bitmapWidth, _bitmapHeight,_displayWidth, _displayHeight;
ScaleGestureDetector _scaleDetector;
Context _context;
public iImage(Context context)
{
super(context);
super.setClickable(true);
_context = context;
_scaleDetector = new ScaleGestureDetector(context, new ScaleListener());
_arrayOf9Floats = new float[9];
setScaleType(ScaleType.MATRIX);
setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return handleTouch(v, event);
}
});
}
private boolean handleTouch(View v, MotionEvent event)
{
_scaleDetector.onTouchEvent(event);
//Contrary to how this line looks, the matrix is not setting the values from the arrayOf9Floats, but rather taking the
//matrix values and assigning them into the arrayOf9Floats. I extremely dislike this syntax and I think
//it should have been written as _arrayOf9Floats = _matrix.getValues() but that's Android for you!!!
_matrix.getValues(_arrayOf9Floats);
//Look at https://youtu.be/IiXB6tYtY4w?t=4m12s , it shows scale, rotate, and translate matrices
//If you look at the translate matrix, you'll see that the 3rd and 6th values are the values which represent x and y translations respectively
//this corresponds to the 2nd and 5th values in the array and hence why the MTRANS_X and MTRANS_Y have the constants 2 and 5 respectively
float xTranslate = _arrayOf9Floats[Matrix.MTRANS_X];
float yTranslate = _arrayOf9Floats[Matrix.MTRANS_Y];
PointF currentEventPoint = new PointF(event.getX(), event.getY());
switch (event.getAction())
{
//First finger down only
case MotionEvent.ACTION_DOWN:
_previousPoint.set(event.getX(), event.getY());
_startPoint.set(_previousPoint);
_mode = DRAG_MODE;
break;
//Second finger down
case MotionEvent.ACTION_POINTER_DOWN:
_previousPoint.set(event.getX(), event.getY());
_startPoint.set(_previousPoint);
_mode = ZOOM_MODE;
break;
case MotionEvent.ACTION_MOVE:
if (_mode == ZOOM_MODE || _mode == DRAG_MODE )
{
float deltaX = currentEventPoint.x - _previousPoint.x;
float deltaY = currentEventPoint.y - _previousPoint.y;
//In matrix terms, going right is + and going left is +
//Moving the image right past 0 means it will show alpha space on the left so we dont want that
//Keep in mind this is a TOP LEFT pivot point, so we dont want the top left to be past 0 lest we have alpha space
if(xTranslate + deltaX > 0)
{
//get absolute of how much into the negative we would have gone
float excessDeltaX = Math.abs(xTranslate + deltaX);
//take that excess away from deltaX so X wont got less than 0 after the translation
deltaX = deltaX - excessDeltaX;
}
//Going left we dont want the negative value to be less than the negative width of the sprite, lest we get alpha space on the right
//The width is going to be the width of the bitmap * scale and we want the - of it because we are checking for left movement
//We also need to account for the width of the DISPLAY CONTAINER (i.e. _displayWidth) so that gets subtracted
//i.e. we want the max scroll width value
float maxScrollableWidth = _bitmapWidth * _currentScale - _displayWidth;
if(xTranslate + deltaX < -maxScrollableWidth)
{
//this forces the max possible translate to always match the - of maxScrollableWidth
deltaX = -maxScrollableWidth - xTranslate;
}
//repeat for Y
if(yTranslate + deltaY > 0)
{
float excessDeltaY = Math.abs(yTranslate + deltaY);
deltaY = deltaY - excessDeltaY;
}
float maxScrollableHeight = _bitmapHeight * _currentScale - _displayWidth;
if(yTranslate + deltaY < -maxScrollableHeight)
{
//this forces the max possible translate to always match the - of maxScrollableWidth
deltaY = -maxScrollableHeight - yTranslate;
}
_matrix.postTranslate(deltaX, deltaY);
_matrix.getValues(_arrayOf9Floats);
//System.out.println(_matrix);
_previousPoint.set(currentEventPoint.x, currentEventPoint.y);
}
break;
case MotionEvent.ACTION_POINTER_UP:
_mode = NONE_MODE;
break;
}
setImageMatrix(_matrix);
invalidate();
return true;
}
@Override
public void setImageBitmap(Bitmap bm)
{
super.setImageBitmap(bm);
_bitmapWidth = bm.getWidth();
_bitmapHeight = bm.getHeight();
invalidate();
}
@Override
public void setImageResource(int resid)
{
Bitmap bitmapImage = BitmapFactory.decodeResource(_context.getResources(), resid);
setImageBitmap(bitmapImage);
}
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener
{
@Override
public boolean onScaleBegin(ScaleGestureDetector detector)
{
_mode = ZOOM_MODE;
return true;
}
@Override
public boolean onScale(ScaleGestureDetector detector)
{
float scaleFactor = detector.getScaleFactor();
float originalScale = _currentScale;
_currentScale *= scaleFactor;
//Zoom in too much
if (_currentScale > _maxScale) {
_currentScale = _maxScale;
scaleFactor = _maxScale / originalScale;
}//Zoom out too much
else if (_currentScale < _minScale) {
_currentScale = _minScale;
scaleFactor = _minScale / originalScale;
}
_matrix.postScale(scaleFactor,scaleFactor);
return true;
}
}
@Override
protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec)
{
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
_displayWidth = MeasureSpec.getSize(widthMeasureSpec);
_displayHeight = MeasureSpec.getSize(heightMeasureSpec);
adjustScale();
}
private void adjustScale()
{
//Fit to display bounds with NO alpha space
float scale;
float scaleX = _displayWidth / _bitmapWidth;
float scaleY = _displayHeight / _bitmapHeight;
scale = Math.max(scaleX, scaleY);
_matrix.setScale(scale, scale);
setImageMatrix(_matrix);
_currentScale = scale;
_minScale = scale;
}
public void setMaxZoom(float maxZoom){_maxScale = maxZoom;}
public void setMinZoom(float minZoom) {_minScale = minZoom;}
}
Этот код работает и реализует двойное нажатие, чтобы вернуться к исходному размеру изображения.
1-й шаг - в вашем XML-макете поместите это:
<com.****.*****.TouchImageView
android:id="@+id/action_infolinks_splash"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@mipmap/myinfolinks_splash"
android:layout_gravity="center"
android:gravity="center"
android:scaleType="fitCenter"
android:contentDescription="@string/aboutSupport_description_image"/>
2-й шаг - создать файл (TouchImageView.java) с классом TouchImageView:
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.widget.ImageView;
public class TouchImageView extends ImageView {
Matrix matrix;
// 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;
// Remember some things for zooming
PointF last = new PointF();
PointF start = new PointF();
float minScale = 1f;
float maxScale = 3f;
float[] m;
float redundantXSpace, redundantYSpace, origRedundantXSpace, origRedundantYSpace;
int viewWidth, viewHeight;
static final int CLICK = 3;
static final float SAVE_SCALE = 1f;
float saveScale = SAVE_SCALE;
protected float origWidth, origHeight;
int oldMeasuredWidth, oldMeasuredHeight;
float origScale, bottom, origBottom, right, origRight;
ScaleGestureDetector mScaleDetector;
GestureDetector mGestureDetector;
Context context;
public TouchImageView(Context context) {
super(context);
sharedConstructing(context);
}
public TouchImageView(Context context, AttributeSet attrs) {
super(context, attrs);
sharedConstructing(context);
}
private void sharedConstructing(Context context) {
super.setClickable(true);
this.context = context;
mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
matrix = new Matrix();
m = new float[9];
setImageMatrix(matrix);
setScaleType(ScaleType.MATRIX);
setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
boolean onDoubleTapEvent = mGestureDetector.onTouchEvent(event);
if (onDoubleTapEvent) {
// Reset Image to original scale values
mode = NONE;
bottom = origBottom;
right = origRight;
last = new PointF();
start = new PointF();
m = new float[9];
saveScale = SAVE_SCALE;
matrix = new Matrix();
matrix.setScale(origScale, origScale);
matrix.postTranslate(origRedundantXSpace, origRedundantYSpace);
setImageMatrix(matrix);
invalidate();
return true;
}
mScaleDetector.onTouchEvent(event);
PointF curr = new PointF(event.getX(), event.getY());
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
last.set(curr);
start.set(last);
mode = DRAG;
break;
case MotionEvent.ACTION_MOVE:
if (mode == DRAG) {
float deltaX = curr.x - last.x;
float deltaY = curr.y - last.y;
float fixTransX = getFixDragTrans(deltaX, viewWidth, origWidth * saveScale);
float fixTransY = getFixDragTrans(deltaY, viewHeight, origHeight * saveScale);
matrix.postTranslate(fixTransX, fixTransY);
fixTrans();
last.set(curr.x, curr.y);
}
break;
case MotionEvent.ACTION_UP:
mode = NONE;
int xDiff = (int) Math.abs(curr.x - start.x);
int yDiff = (int) Math.abs(curr.y - start.y);
if (xDiff < CLICK && yDiff < CLICK) performClick();
break;
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
break;
}
setImageMatrix(matrix);
invalidate();
return true; // indicate event was handled
}
});
mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onDoubleTapEvent(MotionEvent e) {
return true;
}
});
}
public void setMaxZoom(float x) {
maxScale = x;
}
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
@Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
mode = ZOOM;
return true;
}
@Override
public boolean onScale(ScaleGestureDetector detector) {
float mScaleFactor = detector.getScaleFactor();
//float mScaleFactor = (float) Math.min(Math.max(.95f, detector.getScaleFactor()), 1.05);
float origScale = saveScale;
saveScale *= mScaleFactor;
if (saveScale > maxScale) {
saveScale = maxScale;
mScaleFactor = maxScale / origScale;
} else if (saveScale < minScale) {
saveScale = minScale;
mScaleFactor = minScale / origScale;
}
right = viewWidth * saveScale - viewWidth - (2 * redundantXSpace * saveScale);
bottom = viewHeight * saveScale - viewHeight - (2 * redundantYSpace * saveScale);
if (origWidth * saveScale <= viewWidth || origHeight * saveScale <= viewHeight)
matrix.postScale(mScaleFactor, mScaleFactor, viewWidth / 2, viewHeight / 2);
else
matrix.postScale(mScaleFactor, mScaleFactor, detector.getFocusX(), detector.getFocusY());
fixTrans();
return true;
}
}
void fixTrans() {
matrix.getValues(m);
float transX = m[Matrix.MTRANS_X];
float transY = m[Matrix.MTRANS_Y];
float fixTransX = getFixTrans(transX, viewWidth, origWidth * saveScale);
float fixTransY = getFixTrans(transY, viewHeight, origHeight * saveScale);
if (fixTransX != 0 || fixTransY != 0)
matrix.postTranslate(fixTransX, fixTransY);
}
float getFixTrans(float trans, float viewSize, float contentSize) {
float minTrans, maxTrans;
if (contentSize <= viewSize) {
minTrans = 0;
maxTrans = viewSize - contentSize;
} else {
minTrans = viewSize - contentSize;
maxTrans = 0;
}
if (trans < minTrans)
return -trans + minTrans;
if (trans > maxTrans)
return -trans + maxTrans;
return 0;
}
float getFixDragTrans(float delta, float viewSize, float contentSize) {
if (contentSize <= viewSize) {
return 0;
}
return delta;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
viewWidth = MeasureSpec.getSize(widthMeasureSpec);
viewHeight = MeasureSpec.getSize(heightMeasureSpec);
//
// Rescales image on rotation
//
if (oldMeasuredHeight == viewWidth && oldMeasuredHeight == viewHeight || viewWidth == 0 || viewHeight == 0) return;
oldMeasuredHeight = viewHeight;
oldMeasuredWidth = viewWidth;
if (saveScale == 1) {
// Fit to screen.
float scale;
int bmWidth,bmHeight;
Bitmap bm = BitmapFactory.decodeResource(context.getResources(), R.mipmap.myinfolinks_splash);
bmWidth = bm.getWidth();
bmHeight = bm.getHeight();
int w = bmWidth;
int h = bmHeight;
viewWidth = resolveSize(w, widthMeasureSpec);
viewHeight = resolveSize(h, heightMeasureSpec);
float scaleX = (float) viewWidth / (float) bmWidth;
float scaleY = (float) viewHeight / (float) bmHeight;
scale = Math.min(scaleX, scaleY);
matrix.setScale(scale, scale);
saveScale = SAVE_SCALE;
origScale = scale;
// Center the image
redundantYSpace = (float) viewHeight - (scale * (float) bmHeight);
redundantXSpace = (float) viewWidth - (scale * (float) bmWidth);
redundantYSpace /= (float) 2;
redundantXSpace /= (float) 2;
origRedundantXSpace = redundantXSpace;
origRedundantYSpace = redundantYSpace;
matrix.postTranslate(redundantXSpace, redundantYSpace);
origWidth = viewWidth - 2 * redundantXSpace;
origHeight = viewHeight - 2 * redundantYSpace;
right = viewWidth * saveScale - viewWidth - (2 * redundantXSpace * saveScale);
bottom = viewHeight * saveScale - viewHeight - (2 * redundantYSpace * saveScale);
origRight = right;
origBottom = bottom;
setImageMatrix(matrix);
}
fixTrans();
}
}
И, наконец, сделайте звонок в своей основной деятельности:
TouchImageView imgDisplay = (TouchImageView) messageView.findViewById(R.id.id_myImage);
imgDisplay.setMaxZoom(2f);
imgDisplay.setImageResource(R.drawable.myImage);
Я видел много кода, и после моих настроек он работает. Наслаждайтесь!
Шаг 1. Сначала вы добавляете зависимости в файл build.gradle(Module:app).
dependencies {
implementation 'com.jsibbold:zoomage:1.2.0'
}
Шаг 2. Затем создайте класс
ImageFullScreenFragment.java
public class ImageFullScreenFragment{
private ZoomageView ImageZoomageView;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = null;
try {
view = inflater.inflate(R.layout.fragment_image_full_screen, container, false);
ImageZoomageView = view.findViewById(R.id.imageViewImageFullScreen);
ImageZoomageView.setImageResource(R.drawable.image);
} catch (Exception e) {
e.printStackTrace();
}
return view;
}
Шаг 3. Затем создайте XML-файл макета
fragment_image_full_screen.xml
<?xml version="1.0" encoding="utf-8"?>
<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"
android:padding="8dp"
xmlns:app="http://schemas.android.com/apk/res-auto">
<com.jsibbold.zoomage.ZoomageView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:zoomage_restrictBounds="false"
app:zoomage_animateOnReset="true"
app:zoomage_autoResetMode="UNDER"
app:zoomage_autoCenter="true"
app:zoomage_zoomable="true"
app:zoomage_translatable="true"
app:zoomage_minScale="0.6"
app:zoomage_maxScale="8"
android:id="@+id/imageViewImageFullScreen"
/>
</RelativeLayout>
Выход:-
Попробуйте следующее:
package com.example.nwssugeoinformationmobileapplication;
import android.os.Bundle;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Intent;
import android.util.FloatMath;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View.OnTouchListener;
import android.widget.TabHost;
import android.widget.TabHost.TabSpec;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.view.View;
import android.widget.ImageView;
public class MainActivity extends Activity implements OnTouchListener {
private static final String TAG = "Touch";
Matrix matrix = new Matrix();
Matrix savedMatrix = new Matrix();
static final int NONE = 0;
static final int DRAG = 1;
static final int ZOOM = 2;
int mode = NONE;
PointF start = new PointF();
PointF mid = new PointF();
float oldDist = 1f;
private ImageView view;
private float[] matrixValues = new float[9];
private float maxZoom;
private float minZoom;
private float height;
private float width;
private RectF viewRect;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TabHost th = (TabHost) findViewById (R.id.tabhost);
th.setup();
TabSpec specs = th.newTabSpec("tag1");
specs.setContent(R.id.tab1);
specs.setIndicator("Map");
th.addTab(specs);
specs = th.newTabSpec("tag2");
specs.setContent(R.id.tab2);
specs.setIndicator("Search");
th.addTab(specs);
view = (ImageView) findViewById(R.id.imageView1);
Drawable bitmap = getResources().getDrawable(R.drawable.map);
view.setImageDrawable(bitmap);
view.setOnTouchListener(this);
matrix.setTranslate(1f, 1f);
view.setImageMatrix(matrix);
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if(hasFocus){
init();
}
}
private void init() {
maxZoom = 2;
minZoom = 1f;
height = view.getDrawable().getIntrinsicHeight();
width = view.getDrawable().getIntrinsicWidth();
viewRect = new RectF(0, 0, view.getWidth(), view.getHeight());
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menus, menu);
return true;
}
public boolean onOptionsItemSelected(MenuItem item) {
if(item.getItemId()== R.id.item1){
Log.d("Tracks", "Track Us was Clicked");
startActivity(new Intent (MainActivity.this, Tracklocation.class ));
}
if(item.getItemId()== R.id.item2){
Log.d("Updates", "Updates was Clicked");
startActivity(new Intent (MainActivity.this, Updates.class ));
}
if(item.getItemId()== R.id.item3){
Log.d("About Us", "About Us was Clicked");
startActivity(new Intent (MainActivity.this, Horoscope.class ));
}
return super.onOptionsItemSelected(item);
}
@Override
public boolean onTouch(View v, MotionEvent rawEvent) {
ImageView view = (ImageView) v;
view.setScaleType(ImageView.ScaleType.MATRIX);
dumpEvent(rawEvent);
// Handle touch events here...
switch (rawEvent.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
savedMatrix.set(matrix);
start.set(rawEvent.getX(), rawEvent.getY());
Log.d(TAG, "mode=DRAG");
mode = DRAG;
break;
case MotionEvent.ACTION_POINTER_DOWN:
oldDist = spacing(rawEvent);
Log.d(TAG, "oldDist=" + oldDist);
if (oldDist > 10f) {
savedMatrix.set(matrix);
midPoint(mid, rawEvent);
mode = ZOOM;
Log.d(TAG, "mode=ZOOM");
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
Log.d(TAG, "mode=NONE");
break;
case MotionEvent.ACTION_MOVE:
if (mode == DRAG) {
matrix.set(savedMatrix);
// limit pan
matrix.getValues(matrixValues);
float currentY = matrixValues[Matrix.MTRANS_Y];
float currentX = matrixValues[Matrix.MTRANS_X];
float currentScale = matrixValues[Matrix.MSCALE_X];
float currentHeight = height * currentScale;
float currentWidth = width * currentScale;
float dx = rawEvent.getX() - start.x;
float dy = rawEvent.getY() - start.y;
float newX = currentX+dx;
float newY = currentY+dy;
RectF drawingRect = new RectF(newX, newY, newX+currentWidth, newY+currentHeight);
float diffUp = Math.min(viewRect.bottom-drawingRect.bottom, viewRect.top-drawingRect.top);
float diffDown = Math.max(viewRect.bottom-drawingRect.bottom, viewRect.top-drawingRect.top);
float diffLeft = Math.min(viewRect.left-drawingRect.left, viewRect.right-drawingRect.right);
float diffRight = Math.max(viewRect.left-drawingRect.left, viewRect.right-drawingRect.right);
if(diffUp > 0 ){
dy +=diffUp;
}
if(diffDown < 0){
dy +=diffDown;
}
if( diffLeft> 0){
dx += diffLeft;
}
if(diffRight < 0){
dx += diffRight;
}
matrix.postTranslate(dx, dy);
} else if (mode == ZOOM) {
float newDist = spacing(rawEvent);
Log.d(TAG, "newDist=" + newDist);
if (newDist > 10f) {
matrix.set(savedMatrix);
float scale1 = newDist / oldDist;
matrix.getValues(matrixValues);
float currentScale = matrixValues[Matrix.MSCALE_X];
// limit zoom
if (scale1 * currentScale > maxZoom) {
scale1 = maxZoom / currentScale;
} else if (scale1 * currentScale < minZoom) {
scale1 = minZoom / currentScale;
}
matrix.postScale(scale1, scale1, mid.x, mid.y);
}
}
break;
}
view.setImageMatrix(matrix);
return true;
}
@SuppressWarnings("deprecation")
private void dumpEvent(MotionEvent event) {
String names[] = { "DOWN", "UP", "MOVE", "CANCEL", "OUTSIDE",
"POINTER_DOWN", "POINTER_UP", "7?", "8?", "9?" };
StringBuilder sb = new StringBuilder();
int action = event.getAction();
int actionCode = action & MotionEvent.ACTION_MASK;
sb.append("event ACTION_").append(names[actionCode]);
if (actionCode == MotionEvent.ACTION_POINTER_DOWN
|| actionCode == MotionEvent.ACTION_POINTER_UP) {
sb.append("(pid ").append(
action >> MotionEvent.ACTION_POINTER_ID_SHIFT);
sb.append(")");
}
sb.append("[");
for (int i = 0; i < event.getPointerCount(); i++) {
sb.append("#").append(i);
sb.append("(pid ").append(event.getPointerId(i));
sb.append(")=").append((int) event.getX(i));
sb.append(",").append((int) event.getY(i));
if (i + 1 < event.getPointerCount())
sb.append(";");
}
sb.append("]");
Log.d(TAG, sb.toString());
}
/** Determine the space between the first two fingers */
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);
}
/** Calculate the mid point of the first two fingers */
@SuppressLint("FloatMath")
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);
}
}
Вот мое решение, оно основано на решении @alexbirkett.
public class ZoomImageView extends ImageView {
// region . Static fields .
static final int NONE = 0;
static final int DRAG = 1;
static final int ZOOM = 2;
static final int CLICK = 3;
// endregion . Static fields .
// region . Fields .
private int mode = NONE;
private Matrix mMatrix = new Matrix();
private PointF mLastTouch = new PointF();
private PointF mStartTouch = new PointF();
private float minScale = 0.5f;
private float maxScale = 4f;
private float[] mCriticPoints;
private float mScale = 1f;
private float mRight;
private float mBottom;
private float mOriginalBitmapWidth;
private float mOriginalBitmapHeight;
private ScaleGestureDetector mScaleDetector;
//endregion . Fields .
// region . Ctor .
public ZoomImageView(Context context) {
super(context);
init(context);
}
public ZoomImageView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public ZoomImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
// endregion . Ctor .
// region . Overrider .
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int bmHeight = getBmHeight();
int bmWidth = getBmWidth();
float width = getMeasuredWidth();
float height = getMeasuredHeight();
float scale = 1;
// If image is bigger then display fit it to screen.
if (width < bmWidth || height < bmHeight) {
scale = width > height ? height / bmHeight : width / bmWidth;
}
mMatrix.setScale(scale, scale);
mScale = 1f;
mOriginalBitmapWidth = scale * bmWidth;
mOriginalBitmapHeight = scale * bmHeight;
// Center the image
float redundantYSpace = (height - mOriginalBitmapHeight);
float redundantXSpace = (width - mOriginalBitmapWidth);
mMatrix.postTranslate(redundantXSpace / 2, redundantYSpace / 2);
setImageMatrix(mMatrix);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
mScaleDetector.onTouchEvent(event);
mMatrix.getValues(mCriticPoints);
float translateX = mCriticPoints[Matrix.MTRANS_X];
float trnslateY = mCriticPoints[Matrix.MTRANS_Y];
PointF currentPoint = new PointF(event.getX(), event.getY());
switch (event.getAction()) {
//when one finger is touching
//set the mode to DRAG
case MotionEvent.ACTION_DOWN:
mLastTouch.set(event.getX(), event.getY());
mStartTouch.set(mLastTouch);
mode = DRAG;
break;
//when two fingers are touching
//set the mode to ZOOM
case MotionEvent.ACTION_POINTER_DOWN:
mLastTouch.set(event.getX(), event.getY());
mStartTouch.set(mLastTouch);
mode = ZOOM;
break;
//when a finger moves
//If mode is applicable move image
case MotionEvent.ACTION_MOVE:
//if the mode is ZOOM or
//if the mode is DRAG and already zoomed
if (mode == ZOOM || (mode == DRAG && mScale > minScale)) {
// region . Move image.
float deltaX = currentPoint.x - mLastTouch.x;// x difference
float deltaY = currentPoint.y - mLastTouch.y;// y difference
float scaleWidth = Math.round(mOriginalBitmapWidth * mScale);// width after applying current scale
float scaleHeight = Math.round(mOriginalBitmapHeight * mScale);// height after applying current scale
// Move image to lef or right if its width is bigger than display width
if (scaleWidth > getWidth()) {
if (translateX + deltaX > 0) {
deltaX = -translateX;
} else if (translateX + deltaX < -mRight) {
deltaX = -(translateX + mRight);
}
} else {
deltaX = 0;
}
// Move image to up or bottom if its height is bigger than display height
if (scaleHeight > getHeight()) {
if (trnslateY + deltaY > 0) {
deltaY = -trnslateY;
} else if (trnslateY + deltaY < -mBottom) {
deltaY = -(trnslateY + mBottom);
}
} else {
deltaY = 0;
}
//move the image with the matrix
mMatrix.postTranslate(deltaX, deltaY);
//set the last touch location to the current
mLastTouch.set(currentPoint.x, currentPoint.y);
// endregion . Move image .
}
break;
//first finger is lifted
case MotionEvent.ACTION_UP:
mode = NONE;
int xDiff = (int) Math.abs(currentPoint.x - mStartTouch.x);
int yDiff = (int) Math.abs(currentPoint.y - mStartTouch.y);
if (xDiff < CLICK && yDiff < CLICK)
performClick();
break;
// second finger is lifted
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
break;
}
setImageMatrix(mMatrix);
invalidate();
return true;
}
//endregion . Overrides .
// region . Privates .
private void init(Context context) {
super.setClickable(true);
mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
mCriticPoints = new float[9];
setImageMatrix(mMatrix);
setScaleType(ScaleType.MATRIX);
}
private int getBmWidth() {
Drawable drawable = getDrawable();
if (drawable != null) {
return drawable.getIntrinsicWidth();
}
return 0;
}
private int getBmHeight() {
Drawable drawable = getDrawable();
if (drawable != null) {
return drawable.getIntrinsicHeight();
}
return 0;
}
//endregion . Privates .
// region . Internal classes .
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
@Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
mode = ZOOM;
return true;
}
@Override
public boolean onScale(ScaleGestureDetector detector) {
float scaleFactor = detector.getScaleFactor();
float newScale = mScale * scaleFactor;
if (newScale < maxScale && newScale > minScale) {
mScale = newScale;
float width = getWidth();
float height = getHeight();
mRight = (mOriginalBitmapWidth * mScale) - width;
mBottom = (mOriginalBitmapHeight * mScale) - height;
float scaledBitmapWidth = mOriginalBitmapWidth * mScale;
float scaledBitmapHeight = mOriginalBitmapHeight * mScale;
if (scaledBitmapWidth <= width || scaledBitmapHeight <= height) {
mMatrix.postScale(scaleFactor, scaleFactor, width / 2, height / 2);
} else {
mMatrix.postScale(scaleFactor, scaleFactor, detector.getFocusX(), detector.getFocusY());
}
}
return true;
}
}
// endregion . Internal classes .
}
Мне нужно было что-то похожее, но мне нужна была возможность легко получать размеры, а также перетаскивать. Я основал это на ответе, который дал @ Николас Тайлер, и изменил его оттуда.
Возможности включают масштабирование с увеличением / уменьшением, длительное нажатие на вибрацию / выделенное перетаскивание.
Чтобы использовать его, добавьте этот класс CustomZoomView в ваш проект.
public class CustomZoomView extends View implements View.OnTouchListener, View.OnLongClickListener{
private Paint mPaint;
Vibrator v;
static final int NONE = 0;
static final int DRAG = 1;
static final int ZOOM = 2;
static final int MOVE = 3;
private int mode = NONE;
Rect src;
Rect mTempDst = new Rect();
Rect dst = new Rect();
Bitmap mBitmap;
private int mBitmapWidth = -1;
private int mBitmapHeight = -1;
private PointF mStartPoint = new PointF();
private PointF mMiddlePoint = new PointF();
private PointF mStartDragPoint = new PointF();
private PointF mMovePoint = new PointF();
private float oldDist = 1f;
private float scale;
private float oldEventX = 0;
private float oldEventY = 0;
private float oldStartPointX = 0;
private float oldStartPointY = 0;
private int mViewWidth = -1;
private int mViewHeight = -1;
private boolean mDraggable = false;
public CustomZoomView(Context context) {
this(context, null, 0);
}
public CustomZoomView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomZoomView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.setOnTouchListener(this);
this.setOnLongClickListener(this);
v = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
mPaint = new Paint();
mPaint.setColorFilter(new PorterDuffColorFilter(Color.argb(100,255,255,255), PorterDuff.Mode.SRC_IN));
}
@Override
public void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mViewWidth = w;
mViewHeight = h;
}
public void setBitmap(Bitmap bitmap) {
if (bitmap != null) {
src = new Rect();
src.left = 0;
src.top = 0;
src.right = bitmap.getWidth();
src.bottom = bitmap.getHeight();
mBitmap = bitmap;
mBitmapWidth = bitmap.getWidth() * 1;
mBitmapHeight = bitmap.getHeight() * 1;
dst = new Rect();
dst.left = (mViewWidth / 2) - (mBitmapWidth / 2);
dst.top = (mViewHeight / 2) - (mBitmapHeight / 2);
dst.right = (mViewWidth / 2) + (mBitmapWidth / 2);
dst.bottom = (mViewHeight / 2) + (mBitmapHeight / 2);
}
}
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
mStartPoint.set(event.getX(), event.getY());
mStartDragPoint.set(event.getX(), event.getY());
mTempDst.set(dst.left, dst.top, dst.right, dst.bottom);
mode = DRAG;
break;
case MotionEvent.ACTION_POINTER_DOWN:
oldDist = spacing(event);
if (oldDist > 10f) {
midPoint(mMiddlePoint, event);
mode = ZOOM;
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
if (mode == ZOOM) {
mBitmapWidth = dst.right - dst.left;
mBitmapHeight = dst.bottom - dst.top;
}
mode = NONE;
break;
case MotionEvent.ACTION_MOVE:
if (mode == DRAG) {
mMovePoint.x = event.getX();
mMovePoint.y = event.getY();
drag(event);
} else if (mode == ZOOM) {
zoom(event);
} else if (mode == MOVE) {
move(event);
}
break;
}
return false;
}
public void move(MotionEvent event) {
int xChange = (int) (event.getX() - mStartPoint.x);
int yChange = (int) (event.getY() - mStartPoint.y);
dst.left = mTempDst.left + (xChange);
dst.top = mTempDst.top + (yChange);
dst.right = mTempDst.right + (xChange);
dst.bottom = mTempDst.bottom + (yChange);
invalidate();
}
public void drag(MotionEvent event) {
float eventX = event.getX();
float eventY = event.getY();
float spacingX = eventX - mStartDragPoint.x;
float spacingY = eventY - mStartDragPoint.y;
float newPositionLeft = (dst.left < 0 ? spacingX : spacingX * -1) + dst.left;
float newPositionRight = (spacingX) + dst.right;
float newPositionTop = (dst.top < 0 ? spacingY : spacingY * -1) + dst.top;
float newPositionBottom = (spacingY) + dst.bottom;
boolean x = true;
boolean y = true;
if (newPositionRight < 0.0f || newPositionLeft > 0.0f) {
if (newPositionRight < 0.0f && newPositionLeft > 0.0f) {
x = false;
} else {
eventX = oldEventX;
mStartDragPoint.x = oldStartPointX;
}
}
if (newPositionBottom < 0.0f || newPositionTop > 0.0f) {
if (newPositionBottom < 0.0f && newPositionTop > 0.0f) {
y = false;
} else {
eventY = oldEventY;
mStartDragPoint.y = oldStartPointY;
}
}
if (mDraggable) {
if (x) oldEventX = eventX;
if (y) oldEventY = eventY;
if (x) oldStartPointX = mStartDragPoint.x;
if (y) oldStartPointY = mStartDragPoint.y;
}
}
public void zoom(MotionEvent event) {
float newDist = spacing(event);
boolean in = newDist > oldDist;
if (!in && scale < .01f) {
return;
}
scale = newDist / oldDist;
int xChange = (int) ((mBitmapWidth * scale) / 2);
int yChange = (int) ((mBitmapHeight * scale) / 2);
if (xChange > 10 && yChange > 10) { //ADDED THIS TO KEEP IT FROM GOING INVERSE
int xMidPoint = ((dst.right - dst.left) / 2) + dst.left;
int yMidPoint = ((dst.bottom - dst.top) / 2) + dst.top;
dst.left = (int) (float) (xMidPoint - xChange);
dst.top = (int) (float) (yMidPoint - yChange);
dst.right = (int) (float) (xMidPoint + xChange);
dst.bottom = (int) (float) (yMidPoint + yChange);
}
invalidate();
}
/**
* Determine the space between the first two fingers
*/
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);
}
/**
* Calculate the mid point of the first two fingers
*/
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);
}
@Override
public boolean onLongClick(View view) {
if (mode == DRAG) {
if ((mStartPoint.x > dst.left && mStartPoint.x < dst.right) && (mStartPoint.y < dst.bottom && mStartPoint.y > dst.top)
&& (mMovePoint.x > dst.left && mMovePoint.x < dst.right) && (mMovePoint.y < dst.bottom && mMovePoint.y > dst.top)) {
mode = MOVE;
v.vibrate(500);
}
}
return true;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (mode == MOVE) {
canvas.drawBitmap(mBitmap, src, dst, null);
canvas.drawBitmap(mBitmap, src, dst, mPaint);
} else {
canvas.drawBitmap(mBitmap, src, dst, null);
}
}
}
... затем добавьте это в свою деятельность
CustomZoomView customImageView = (CustomZoomView) findViewById(R.id.customZoomView);
customImageView.setBitmap(yourBitmap);
... и это на ваш взгляд в XML.
<your.package.name.CustomZoomView
android:id="@+id/customZoomView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:longClickable="true"/>
... и добавить это в свой манифест
<uses-permission android:name="android.permission.VIBRATE"/>
Метод вызова диалога "О программе и поддержке"
public void setupAboutSupport() {
try {
// The About&Support AlertDialog is active
activeAboutSupport=true;
View messageView;
int orientation=this.getResources().getConfiguration().orientation;
// Inflate the about message contents
messageView = getLayoutInflater().inflate(R.layout.about_support, null, false);
ContextThemeWrapper ctw = new ContextThemeWrapper(this, R.style.MyCustomTheme_AlertDialog1);
AlertDialog.Builder builder = new AlertDialog.Builder(ctw);
builder.setIcon(R.mipmap.ic_launcher);
builder.setTitle(R.string.action_aboutSupport);
builder.setView(messageView);
TouchImageView imgDisplay = (TouchImageView) messageView.findViewById(R.id.action_infolinks_about_support);
imgDisplay.setMaxZoom(3f);
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.myinfolinks_about_support);
int imageWidth = bitmap.getWidth();
int imageHeight = bitmap.getHeight();
int newWidth;
// Calculate the new About_Support image width
if(orientation==Configuration.ORIENTATION_PORTRAIT ) {
// For 7" up to 10" tablets
//if ((getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_XLARGE) {
if (SingletonMyInfoLinks.isTablet) {
// newWidth = widthScreen - (two borders of about_support layout and 20% of width Screen)
newWidth = widthScreen - ((2 * toPixels(8)) + (int)(widthScreen*0.2));
} else newWidth = widthScreen - ((2 * toPixels(8)) + (int)(widthScreen*0.1));
} else {
// For 7" up to 10" tablets
//if ((getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_XLARGE) {
if (SingletonMyInfoLinks.isTablet) {
newWidth = widthScreen - ((2 * toPixels(8)) + (int)(widthScreen*0.5));
} else newWidth = widthScreen - ((2 * toPixels(8)) + (int)(widthScreen*0.3));
}
// Get the scale factor
float scaleFactor = (float)newWidth/(float)imageWidth;
// Calculate the new About_Support image height
int newHeight = (int)(imageHeight * scaleFactor);
// Set the new bitmap corresponding the adjusted About_Support image
bitmap = Bitmap.createScaledBitmap(bitmap, newWidth, newHeight, true);
// Rescale the image
imgDisplay.setImageBitmap(bitmap);
dialogAboutSupport = builder.show();
TextView textViewVersion = (TextView) dialogAboutSupport.findViewById(R.id.action_strVersion);
textViewVersion.setText(Html.fromHtml(getString(R.string.aboutSupport_text1)+" <b>"+versionName+"</b>"));
TextView textViewDeveloperName = (TextView) dialogAboutSupport.findViewById(R.id.action_strDeveloperName);
textViewDeveloperName.setText(Html.fromHtml(getString(R.string.aboutSupport_text2)+" <b>"+SingletonMyInfoLinks.developerName+"</b>"));
TextView textViewSupportEmail = (TextView) dialogAboutSupport.findViewById(R.id.action_strSupportEmail);
textViewSupportEmail.setText(Html.fromHtml(getString(R.string.aboutSupport_text3)+" "+SingletonMyInfoLinks.developerEmail));
TextView textViewCompanyName = (TextView) dialogAboutSupport.findViewById(R.id.action_strCompanyName);
textViewCompanyName.setText(Html.fromHtml(getString(R.string.aboutSupport_text4)+" "+SingletonMyInfoLinks.companyName));
Button btnOk = (Button) dialogAboutSupport.findViewById(R.id.btnOK);
btnOk.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dialogAboutSupport.dismiss();
}
});
dialogAboutSupport.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(final DialogInterface dialog) {
// the About & Support AlertDialog is closed
activeAboutSupport=false;
}
});
dialogAboutSupport.getWindow().setBackgroundDrawable(new ColorDrawable(SingletonMyInfoLinks.atualBackgroundColor));
/* Effect that image appear slower */
// Only the fade_in matters
AlphaAnimation fade_out = new AlphaAnimation(1.0f, 0.0f);
AlphaAnimation fade_in = new AlphaAnimation(0.0f, 1.0f);
AlphaAnimation a = false ? fade_out : fade_in;
a.setDuration(2000); // 2 sec
a.setFillAfter(true); // Maintain the visibility at the end of animation
// Animation start
ImageView img = (ImageView) messageView.findViewById(R.id.action_infolinks_about_support);
img.startAnimation(a);
} catch (Exception e) {
//Log.e(SingletonMyInfoLinks.appNameText +"-" + getLocalClassName() + ": ", e.getMessage());
}
}
Просто измените ACTION_MOVE_EVENT в Chirag Raval Answer, чтобы установить ZOOM_IN LIMIT
float[] values = new float[9]; matrix.getValues(values);
//0.37047964 is limit for zoom in
if(values[Matrix.MSCALE_X]>0.37047964) {
matrix.set(savedMatrix);
matrix.postScale(scale, scale, mid.x, mid.y);
view.setImageMatrix(matrix);
}else if (scale>1){
matrix.set(savedMatrix);
matrix.postScale(scale, scale, mid.x, mid.y);
view.setImageMatrix(matrix);
}
Я знаю, что уже немного поздно для этого ответа, но я надеюсь, что это кому-то поможет.
Я искал то же самое (масштабирование с помощью пинча и перетаскивания изображения) и нашел ссылку на блог для разработчиков Android.
Работает отлично. Никаких артефактов или чего-либо еще. Оно использует ScaleGestureDetector
,
Ссылка ZoomLib: https://drive.google.com/uc?export=download&id=0B34PUThnUsjVaHpkaGk0Z1hSRU0
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.dummy_layout_for_zooming);// Activity layout
mZoomLinearLayout = (LinearLayout) findViewById(R.id.mZoomLinearLayout);// LinearLayout inside Activity layout
View v = ((LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.layout_for_zoom, null, false);// View wants to zoom
v.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.FILL_PARENT));
ZoomView zoomView = new ZoomView(this);// intialize lib
zoomView.addView(v);
mZoomLinearLayout.addView(zoomView);
}
Если вы хотите установить масштаб изображения перед показом, используйте этот класс: https://github.com/MikeOrtiz/TouchImageView/blob/master/src/com/ortiz/touch/TouchImageView.java.
Также изображение может быть изменено с двойным нажатием.
Если вы используете ImageView
внутри ViewPager
, примените это исправление: https://github.com/MikeOrtiz/TouchImageView/issues/125.
Я думаю, почему вы хотите, чтобы увеличить в и уменьшить масштаб изображения вида потому, что ваш вид изображения мал и масштабирование изображения не позволит изображению выйти из представления изображения. Вместо этого изображение начинает исчезать из границ при увеличении масштаба. Я думаю, вы хотите, чтобы изображение выходило за пределы изображения, пока мы увеличиваем масштаб.
Итак, есть два приема (по моему мнению), чтобы добиться этого:
- Измените параметры макета представления изображения, чтобы охватить весь внешний вид или группу представлений во время выполнения, пока мы собираемся увеличить изображение.
- Создайте развернутый вид изображения или полноэкранный вид (высота и ширина = внешний вид или группа представлений) в XML-файле и установите его видимость. Когда мы собираемся увеличить изображение, загрузите изображение из small Image View в полное Img View, сопоставьте изображение в fullImgView с изображением в smallImgView и сделайте его видимым.
Уловка № 1 не работает, когда представление изображения очень сильно вложено в другие представления (например, в представлении вложенного ресайклера)
Уловки нет.2 работает всегда:-)
Вот реализация трюка №2 -
public class ZoomOnTouchListener extends AppCompatActivity implements View.OnTouchListener {
private Matrix matrix = new Matrix();
private boolean isfullImgViewActive = false;
// above boolean gets true when when we firstly move 2 fingers on the smallImgView and in this case smallImgView gets invisible and fullImgView gets visible
// and false if smallImgView is visible and fullImgView is gone
private float[] matrixArray = new float[9];
private float orgScale;
private PointF start = new PointF();
private PointF prevP1 = new PointF();
private PointF prevP2 = new PointF();
private PointF mid = new PointF();
private float oldDist = 1f;
private ImageView mfullImgView;
private ImageView smallImgView;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mfullImgView = (ImageView)findViewById(R.id.imgView2);
mfullImgView.setVisibility(View.GONE);
smallImgView = (ImageView)findViewById(R.id.imgView);
smallImgView.setOnTouchListener(this);
}
@Override
public boolean onTouch(View v, MotionEvent event) {
//Log.i("0", "OnTouch()");
if(v instanceof ImageView) {
ImageView imgView = (ImageView) v;
boolean isImgViewSmall = (imgView == smallImgView);
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN: // first finger down only
//Log.i("T", "Motion Event: ACTION_DOWN");
if(isImgViewSmall)
start.set(event.getX(), event.getY());
prevP1.set(event.getX(), event.getY());
return true;
case MotionEvent.ACTION_POINTER_DOWN: //second finger and other fingers down
prevP1.set(event.getX(0), event.getY(0));
prevP2.set(event.getX(1), event.getY(1));
oldDist = spacing(event);
midPoint(mid, event);
break;
case MotionEvent.ACTION_MOVE: //it doesn't mean fingers are moved. In this case, all pointers which are active are batched together
// this case occurs after action_down or action_pointer_down
//Log.i("Tag", event.getX()+","+event.getY());
if(event.getPointerCount() == 2) {
PointF newMid = new PointF();
midPoint(newMid,event);
float newDist = spacing(event);
float scale = newDist/oldDist;
if( !isfullImgViewActive){ // is smallImgView is visible and mfullImgView is gone
Log.i("tag", "true");
isfullImgViewActive = true;
matrix.set(imgView.getImageMatrix()); //note:- do not write matrix = imgView.getImageMatrix() because it gives the smallImgView's matrix reference to the matrix variable and changes on matrix will reflect on smallImgView
matrix.getValues(matrixArray);
orgScale = matrixArray[0];
smallImgView.setVisibility(View.INVISIBLE);
mfullImgView.setImageDrawable(smallImgView.getDrawable());
mfullImgView.setScaleType(ImageView.ScaleType.MATRIX);
mfullImgView.setVisibility(View.VISIBLE);
//To map the image of mFullImgView to that of smallImgView we have to
// translate the mFullImgView's image
matrix.postTranslate(tx, ty);
/////////////NOTE///////////////
//here (tx,ty) are coordinates of top-left corner of smallimgView and
// they MUST be relative to the origin of Outermost view or view group
// where fullImgView is placed. So find tx,ty in your case by yourself
mfullImgView.setImageMatrix(matrix);
}
if(isImgViewSmall) {
matrix.postScale(scale, scale, mid.x + tx, mid.y + ty);
}
else{
matrix.postScale(scale, scale, mid.x, mid.y);
}
oldDist = newDist;
matrix.postTranslate(newMid.x - mid.x, newMid.y - mid.y);
matrix.getValues(matrixArray);
mid.set(newMid);
prevP1.set(event.getX(0), event.getY(0));
prevP2.set(event.getX(1), event.getY(1));
}
else if(event.getPointerCount() == 1 ){
if(isfullImgViewActive) {
matrix.postTranslate(event.getX() - prevP1.x, event.getY() - prevP1.y);
matrix.getValues(matrixArray);
}
prevP1.set(event.getX(0), event.getY(0));
}
break;
case MotionEvent.ACTION_POINTER_UP: // second finger lifted
//Now if pointer of index 0 is lifted then pointer of index 1 will get index 0;
if(event.getActionIndex() == 0 && isfullImgViewActive){
Log.i("TAg", event.getActionIndex()+"");
prevP1.set(prevP2);
}
break;
case MotionEvent.ACTION_UP: // first finger lifted or all fingers are lifted
if(isImgViewSmall && !isfullImgViewActive) {
imgView.setScaleType(ImageView.ScaleType.FIT_CENTER);
int xDiff = (int) Math.abs(event.getX() - start.x);
int yDiff = (int) Math.abs(event.getY() - start.y);
if (xDiff == 0 && yDiff == 0) {
imgView.performClick();
return true;
}
}
if(isfullImgViewActive){
if(matrixArray[0] <= orgScale){ //matrixArray[0] is Scale.X value
mfullImgView.setOnTouchListener(null);
mfullImgView.setImageDrawable(null);
mfullImgView.setVisibility(View.GONE);
smallImgView.setOnTouchListener(this);
smallImgView.setScaleType(ImageView.ScaleType.FIT_CENTER);
smallImgView.setVisibility(View.VISIBLE);
isfullImgViewActive = false;
}
else if(matrixArray[0] > orgScale && isImgViewSmall){ //if the imgView was smallImgView
smallImgView.setOnTouchListener(null);
smallImgView.setScaleType(ImageView.ScaleType.FIT_CENTER);
smallImgView.setVisibility(View.GONE); // or View.INVISIBLE
mfullImgView.setOnTouchListener(this);
}
}
return true;
}
//end of Switch statement
if(isfullImgViewActive) { //active means visible
mfullImgView.setImageMatrix(matrix); // display the transformation on screen
}
return true; // indicate event was handled
}
else
return false;
}
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);
}
}
ПРИМЕЧАНИЕ. - Не устанавливайте OnClickListener на mfullImgView перед установкой для него onTouchListener. Настройка, которая позволит fullImageView(если он виден) украсть событие касания опускания второго пальца после его первого подъема, потому что мы хотим, чтобы smallImgView принимал все события касания, пока все пальцы не будут подняты для первого. время.
Я использую этот, он работает отлично.
<your.packagename.MyZoomableImageViewTouch
android:id="@+id/mediaImage"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scaleType="matrix"/>
Мой класс MyZoomableImageViewTouch ниже:
public class MyZoomableImageViewTouch extends ImageViewTouch
{
static final float SCROLL_DELTA_THRESHOLD = 1.0f;
public MyZoomableImageViewTouch(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
init();
}
public MyZoomableImageViewTouch(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public MyZoomableImageViewTouch(Context context)
{
super(context);
init();
}
private void init() {
View.OnTouchListener listener = new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (getScale() > 1f) {
getParent().requestDisallowInterceptTouchEvent(true);
} else {
getParent().requestDisallowInterceptTouchEvent(false);
}
return false;
}
};
setOnTouchListener(listener);
setDisplayType(DisplayType.FIT_TO_SCREEN);
}
@Override
protected float onDoubleTapPost(float scale, float maxZoom) {
if (scale != 1f) {
mDoubleTapDirection = 1;
return 1f;
}
if (mDoubleTapDirection == 1) {
mDoubleTapDirection = -1;
if ((scale + (mScaleFactor * 2)) <= maxZoom) {
return scale + mScaleFactor;
} else {
mDoubleTapDirection = -1;
return maxZoom;
}
} else {
mDoubleTapDirection = 1;
return 1f;
}
}
@Override
public boolean canScroll(int direction) {
RectF bitmapRect = getBitmapRect();
updateRect(bitmapRect, mScrollRect);
Rect imageViewRect = new Rect();
getGlobalVisibleRect(imageViewRect);
if (null == bitmapRect) {
return false;
}
if (Math.abs(bitmapRect.right - imageViewRect.right) < SCROLL_DELTA_THRESHOLD) {
if (direction < 0) {
return false;
}
}
if (Math.abs(bitmapRect.left - mScrollRect.left) < SCROLL_DELTA_THRESHOLD) {
if (direction > 0) {
return false;
}
}
return true;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY)
{
if (getScale() == 1f) return false;
if (distanceX != 0 && !canScroll((int) -distanceX)) {
getParent().requestDisallowInterceptTouchEvent(false);
return false;
} else {
getParent().requestDisallowInterceptTouchEvent(true);
mUserScaled = true;
scrollBy(-distanceX, -distanceY);
invalidate();
return true;
}
}
}