我想放大和缩小 Android ImageView。我尝试了大多数示例,但在所有示例中,ImageView 本身的图像都被放大和缩小,而我想放大和缩小 ImageView。我想在放大时增加 ImageView 的宽度和高度,并在缩小时减少 ImageView 的宽度和高度。我该如何做到这一点?
one line of code
请遵循以下课程,该课程用于 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
matrix.set(view.getImageMatrix());
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"/>
saveScale
是图像的当前缩放值,minScale
是它可以走的最小值,maxScale
是图像可以缩放的最大值。
setOnTouchListener()
,您只需覆盖 public boolean onTouchEvent(MotionEvent event)
简单的方法:
PhotoViewAttacher pAttacher;
pAttacher = new PhotoViewAttacher(Your_Image_View);
pAttacher.update();
在 build.gradle
中添加以下行:
compile 'com.commit451:PhotoView:1.2.4'
制作两个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));
}
}
我已经改进了从堆栈中获得的完美缩放(两指)/旋转(两指)/拖动(单指)的答案。
https://i.stack.imgur.com/wRYvn.png
//============================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() 方法。非常适用于 textview 缩放。它不会像素化文本。
它很旧,但这可能对其他人有所帮助。
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
替换为 XML 和 XML 中的 TouchImageView爪哇
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);
这是另一个基于 Nicolas Tyler 发布的代码的实现。
修复了以下错误:
现在将 minScale 设置为小于 1 的数字有效
您不需要使用 setImageBitmap() 来设置图像(您可以使用,例如 setImageResource()
现在所有构造函数都可以正常工作
整理了以下内容:
不使用 OnTouchListener,它不是必需的,因为该类可以只实现 onTouchEvent() 方法。
赋值权=宽度*saveScale-宽度-(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://stackoverflow.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;
}
}
ImageView
时有没有办法恢复图像的缩放?
ViewPager
中使用此小部件,则会出现一些困难。 1) 前后移动后比例尺不重置为 1。 2) 如果您尝试移动图片,则移动缓慢且短促。你可以偶尔移动到下一张图片。这不是解决方案的问题,但您应该意识到一种新的行为。
onScale
方法中添加了 getWidth()
和 getHeight()
,它们的实现在哪里?
我用捏缩放制作了自己的自定义图像视图。 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
我认为 Chirag Ravals 的回答很棒!
唯一可以改进的是将所有这些代码移动到某个类中,例如:
PinchZoomImageView extends ImageView {...
并在那里添加初始图像矩阵初始化以防止在第一次点击后缩放:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
matrix = new Matrix(this.getImageMatrix());
}
顺便说一句,这将修复 Muhammad Umar 和 Baz 提到的错误
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);
}
matrix = new Matrix(this.getImageMatrix());
行使图像对我来说消失了。你知道为什么吗?
我从@Nicolas Tyler 那里得到了最有帮助的答案,但我对语法和逻辑的工作方式有疑问。我也不想要任何阿尔法空间,我的代数生锈了! 3天后,我整理了自己的版本。
我的回答与@Nicolas Tyler 的不同之处在于:
我发现不同的变量名称在底层上下文使用中更有意义 这个 Pinch-Zoom 图像类不显示 alpha 空间,并且可以让你放大和缩小,但仍然不能让你在平移图像上/下平移并显示 alpha 空间 添加了深刻的评论到矩阵部分来解释所涉及的数学发生了什么这个图像类还将让您传入一个resourceId,它会从中创建一个位图 缩放和平移的算法更简单,变量很少 在其中更改图像将使其放大/缩小,以便新图像占据视图容器
可以在此处找到有关代数的重要资源复习: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;}
}
mMatrix.postScale(scaleFactor, scaleFactor);
替换为 public boolean onScale(ScaleGestureDetector detector)
内的 mMatrix.postScale(scaleFactor, scaleFactor, detector.getFocusX(), detector.getFocusY());
可以解决问题。需要更多代码来支持缩小。但就目前而言,这对我来说已经足够了。
android:src
和 android:scaleType
。如何将“可绘制”文件夹中的图像添加到其中。
adjustScale()
中使用 scale = Math.min(scaleX, scaleY);
。* 缩放不遵循手指之间的中点
此代码有效并实现双击以返回原始图像大小。
第一步 - 在您的 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"/>
第二步 - 使用 TouchImageView 类创建一个文件 (TouchImageView.java):
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>
输出:-
https://i.stack.imgur.com/l5vRq.png
https://i.stack.imgur.com/9gdNN.png
https://i.stack.imgur.com/v6Hj5.png
您应该将图像放在 webview 中并使用它。放大/缩小控件在 webview 中可用。
http://xjaphx.wordpress.com/2011/09/18/using-webview-as-a-image-zoom-view-control/
http://androidforums.com/android-lounge/121522-how-display-image-sdcard-webview.html
尝试以下操作:
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);
}
}
我需要类似的东西,但需要能够轻松获取尺寸并拖放。我基于@Nicolas Tyler 给出的答案并从那里修改它。
功能是捏放大/缩小,长按振动/突出显示拖放。
要使用它,请将此 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"/>
这是我的解决方案,它基于@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 .
}
调用关于&支持对话框的方法
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());
}
}
只需更改 Chirag Raval Answer 中的 ACTION_MOVE_EVENT 即可设置 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);
}
我知道这个答案有点晚了,但我希望它对某人有所帮助。
我一直在寻找相同的东西(使用捏合缩放和拖动图像),我找到了 this Android Developers Blog link。
完美运行。没有文物或任何东西。它使用 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);
}
我认为你为什么要放大和缩小图像视图是因为你的图像视图很小并且放大图像不会让图像从图像视图中出来。相反,图像在放大时开始从边界消失。所以我猜想在我们放大时让图像从图像中出来是你想要的。
所以有两个技巧(根据我)来实现这一点 -
在我们即将放大图像时,更改图像视图的布局参数以在运行时覆盖整个最外层视图或视图组。在 xml 文件中创建扩展的图像视图或完整图像视图(高度和宽度 = 最外层视图或视图组)并将其可见性设置为消失。当我们要放大图像时,将图像从small Image View加载到full 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);
}
}
注意:- 在将 onTouchListener 设置为之前,不要将 OnClickListener 设置为 mfullImgView。设置这将让 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;
}
}
}
ImageView
本身设置为centerFit
。case MotionEvent.ACTION_DOWN: // first finger down only matrix.set(view.getImageMatrix()); savedMatrix.set(matrix);
这会将当前缩放设置复制到初始matrix