ChatGPT解决这个技术问题 Extra ChatGPT

Android ImageView 放大和缩小

我想放大和缩小 Android ImageView。我尝试了大多数示例,但在所有示例中,ImageView 本身的图像都被放大和缩小,而我想放大和缩小 ImageView。我想在放大时增加 ImageView 的宽度和高度,并在缩小时减少 ImageView 的宽度和高度。我该如何做到这一点?

Google 提供了一个放大/缩小视图的示例:developer.android.com/training/animation/zoom.html
看看this answer它的真棒和one line of code
这个来自 Android 的示例非常可靠,提供了分步说明和源代码。 developer.android.com/training/animation/zoom.html

N
Nikunj Paradva

请遵循以下课程,该课程用于 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());
    }
}

每当我点击图像时,它都会缩放。我该怎么做才能阻止它
我非常感谢您对上述评论的回答。同样的事情发生在我身上。有什么办法可以阻止它在第一次点击时放大? ImageView 本身设置为 centerFit
@Baz,为避免在第一次点击时放大,请使用 case MotionEvent.ACTION_DOWN: // first finger down only matrix.set(view.getImageMatrix()); savedMatrix.set(matrix); 这会将当前缩放设置复制到初始 matrix
我们如何将图像保留在屏幕中?因为我可以继续滚动它,直到它完全看不见为止。
对于使用上述代码的人,“return FloatMath.sqrt(x * x + y * y);”将其替换为“return (float)Math.sqrt(x * x + y * y);”因为 FloatMath 现在已被弃用。干杯
N
Nicolas Tyler

这里的其他实现都有某种缺陷。所以我基本上把它们混在一起并想出了这个。

创建一个像这样的自定义视图:

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"/>

这取决于您喜欢哪种比例类型。
我没有说您应该将 scaletype 更改为 fitXy ...如果您更改代码,它不起作用不是我的错。我为您提供了我以前使用过的有效解决方案。
我会添加注释,但它并不复杂,saveScale 是图像的当前缩放值,minScale 是它可以走的最小值,maxScale 是图像可以缩放的最大值。
无需使用 setOnTouchListener(),您只需覆盖 public boolean onTouchEvent(MotionEvent event)
当图像在 ViewPager 中时不起作用。显示空白屏幕。虽然类似的解决方案和衍生项目有效
V
Vishal Yadav

简单的方法:

PhotoViewAttacher pAttacher;
pAttacher = new PhotoViewAttacher(Your_Image_View);
pAttacher.update();

build.gradle 中添加以下行:

compile 'com.commit451:PhotoView:1.2.4'

很好,但这仅适用于 imageview。如何将 View 扩展的类附加到此附加器。你有什么想法,
这很好用。我尝试了其他答案,但它们没有工作,或者没有正常工作。
这是一个过时的版本。有关最新 PhotoView 的说明,请参阅存储库:github.com/chrisbanes/PhotoView
尽管根据上述链接说明的 PhotoView 它不起作用。您的答案(PhotoViewAttacher)似乎有效
S
Simulant

制作两个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));
   }
}

我遇到了错误... image=context.getResources().getDrawable(R.drawable.j);我在可绘制文件夹中复制图像。我将图像重命名为 j.. 我得到 j 无法解析或不是字段..
@chinna_82,图片应该是 j.png,你应该把它放在 Drawable 文件夹中。然后刷新您的项目,错误不应该是
如何在 viewpager 之外缩放意味着整个屏幕?
A
Aman Srivastava

我已经改进了从堆栈中获得的完美缩放(两指)/旋转(两指)/拖动(单指)的答案。

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 缩放。它不会像素化文本。


出色的解决方案,不错的方法。谢谢你
Z
Zain

它很旧,但这可能对其他人有所帮助。

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);

我从 setImageURI(imageUri) 开始,每个图像都显示为黑色......视图确实获得了正确的大小、高度和不同的属性,但无论图像如何,都不会显示任何内容。
@SuppressWarnings 感谢您的通知,我不确定我是否尝试以编程方式设置它;需要回头看..并会提到您的任何解决方法:)
这有效,但它没有放大到您双击 + 捏放大的区域有一定的限制。
A
Anjula

只需使用此类:TouchImageView


遵循我们的社区准则。不要提供外部链接,因为将来可能无法访问链接。此外,提供一些片段代码。
a
alexbirkett

这是另一个基于 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;
    }
}

很好。我修改了一点你的代码。如果宽度或高度小于显示范围,我禁用了在 X 或 Y 上移动图像的功能
@ROHITPARMAR 我将在我的班级发表新评论。
双击 ImageView 时有没有办法恢复图像的缩放?
谢谢!效果很好。如果您在 ViewPager 中使用此小部件,则会出现一些困难。 1) 前后移动后比例尺不重置为 1。 2) 如果您尝试移动图片,则移动缓慢且短促。你可以偶尔移动到下一张图片。这不是解决方案的问题,但您应该意识到一种新的行为。
您在 onScale 方法中添加了 getWidth()getHeight(),它们的实现在哪里?
C
Community

我用捏缩放制作了自己的自定义图像视图。 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

好的,到目前为止最好的实现。我对这个实现的主要问题是,从一开始,图像就以 1:1 的比例显示,我们无法执行缩小。除此之外,到目前为止,这是我在这个线程上最喜欢的实现
g
goRGon

我认为 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()); 行使图像对我来说消失了。你知道为什么吗?
如果您在 onMeasure() 内部执行此操作,则矩阵将根据当前视图缩放默认比例获得正确的值。并且这个矩阵只会在与用户的下一次交互之后使用(例如点击)。你的形象是什么时候消失的?
@goRGon嗨,在我的应用程序中,我设置了适合屏幕的图像。而且我想放大屏幕尺寸,这工作正常。而且我需要缩小,拖动,旋转仅在屏幕外部而不是在屏幕内部完成的图像。请帮我怎么做。
A
Aggressor

我从@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()); 可以解决问题。需要更多代码来支持缩小。但就目前而言,这对我来说已经足够了。
谁能告诉我如何初始化它?在主要活动中。我从 xml 文件中删除了 android:srcandroid:scaleType。如何将“可绘制”文件夹中的图像添加到其中。
这有一些问题: * 初始缩放错误(可能的解决方案在 adjustScale() 中使用 scale = Math.min(scaleX, scaleY);。* 缩放不遵循手指之间的中点
j
jmtsilva69

此代码有效并实现双击以返回原始图像大小。

第一步 - 在您的 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);

我看到了很多代码,经过我的调整,它开始工作了。享受!


为了更好地执行更改此行: Bitmap bm = BitmapFactory.decodeResource(context.getResources(), R.mipmap.myinfolinks_splash);对于这个: ImageView img = (ImageView) findViewById(R.id.action_infolinks_splash);
而且你不需要这个(它已经在 xml 布局中设置): imgDisplay.setImageResource(R.mipmap.myinfolinks_splash);
Skizo-this: ImageView img = (ImageView) findViewById(R.id.action_infolinks_splash)
Skizo- this: ImageView img = (ImageView) findViewById(R.id.action_infolinks_splash) 用于以编程方式获取宽度和高度图像。昨天我改进了重新缩放的代码,我只使用了 xxhdpi jpg 图像(1026 像素 x 770 像素),就像我制作了更小的应用程序,并且成功地调整了所有屏幕尺寸的图像。
在 xml 中: <***.****.TouchImageView android:id="@+id/action_infolinks_about_support" android:layout_width="match_parent" android:layout_height="wrap_content" android:src="@mipmap/myinfolinks_about_support" android :scaleType="centerInside" android:contentDescription="@string/aboutSupport_description_image"/>
P
Pramesh Bhalala

第 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


j
j0k

您应该将图像放在 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


J
Josh Crozier

尝试以下操作:

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);
        }
}

a
a54studio

我需要类似的东西,但需要能够轻松获取尺寸并拖放。我基于@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"/>

H
Hardik

这是我的解决方案,它基于@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 .
}

如果这不起作用,请尝试扩展 android.support.v7.widget.AppCompatImageView。
你好,你能告诉我如何在主类中使用它吗?我想出了这个,你能告诉我下一个应该是什么吗? ZoomableImageView touch =(ZoomableImageView)findViewById(R.id.image1);
O
Ovi

调用关于&支持对话框的方法

 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());
    }
}

s
shashank sachdev

只需更改 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);
                }

M
Mahsa2

我知道这个答案有点晚了,但我希望它对某人有所帮助。

我一直在寻找相同的东西(使用捏合缩放和拖动图像),我找到了 this Android Developers Blog link

完美运行。没有文物或任何东西。它使用 ScaleGestureDetector


S
Saurabh Bhandari

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);
}

G
Gaganpreet Bagga

我认为你为什么要放大和缩小图像视图是因为你的图像视图很小并且放大图像不会让图像从图像视图中出来。相反,图像在放大时开始从边界消失。所以我猜想在我们放大时让图像从图像中出来是你想要的。

所以有两个技巧(根据我)来实现这一点 -

在我们即将放大图像时,更改图像视图的布局参数以在运行时覆盖整个最外层视图或视图组。在 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 接受所有触摸事件,直到所有手指都第一次抬起时间。


K
Komal12

我正在使用这个,它工作得很好。

<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;
        }
    }
}

您的示例代码不完整,错误很多,并且缺少 ImageViewTouch 类。