Android ImageView Phóng to và Thu nhỏ


114

Tôi muốn Phóng to và Thu nhỏ một Android ImageView. Tôi đã thử hầu hết các mẫu nhưng trong tất cả các mẫu đó, bản thân hình ảnh trong ImageView đang được Phóng to và Thu nhỏ, trong khi tôi muốn Phóng to và Thu nhỏ ImageView. Tôi muốn tăng chiều rộng và chiều cao của ImageView trong khi Phóng to và giảm chiều rộng và chiều cao của ImageView trong khi Thu nhỏ. Làm cách nào để đạt được điều đó?



1
Google đã cung cấp một ví dụ để thực hiện chế độ xem phóng to / thu nhỏ: developer.android.com/training/animation/zoom.html
Kai

1
hãy xem câu trả lời này thật tuyệt vời vàone line of code
Basheer AL-MOMANI

Ví dụ này từ Android khá chắc chắn, hướng dẫn từng bước và mã nguồn được cung cấp. developer.android.com/training/animation/zoom.html
Al-Kathiri Khalid

Câu trả lời:


25

Tạo hai lớp java

Thu phóng lớp

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

làm lớp thứ hai

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

tôi gặp lỗi trong ... image = context.getResources (). getDrawable (R.drawable.j); Tôi sao chép một hình ảnh trong thư mục có thể vẽ được. Tôi đổi tên hình ảnh để j .. Tôi có j không thể được giải quyết hay không là một lĩnh vực ..
chinna_82

@ chinna_82, hình ảnh phải là j.png và bạn nên đặt nó trong thư mục Drawable. Sau đó làm mới dự án của bạn và lỗi không nên
KhalidTaha

1
làm cách nào để tôi có thể phóng to bên ngoài viewpager có nghĩa là toàn bộ màn hình?
MD Khali

211

Vui lòng làm theo lớp dưới đây, được sử dụng để Phóng to và Thu nhỏ cho ImageView.

import android.app.Activity;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.ImageView;

public class ZoomInZoomOut extends Activity implements OnTouchListener 
{
    private static final String TAG = "Touch";
    @SuppressWarnings("unused")
    private static final float MIN_ZOOM = 1f,MAX_ZOOM = 1f;

    // These matrices will be used to scale points of the image
    Matrix matrix = new Matrix();
    Matrix savedMatrix = new Matrix();

    // The 3 states (events) which the user is trying to perform
    static final int NONE = 0;
    static final int DRAG = 1;
    static final int ZOOM = 2;
    int mode = NONE;

    // these PointF objects are used to record the point(s) the user is touching
    PointF start = new PointF();
    PointF mid = new PointF();
    float oldDist = 1f;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        ImageView view = (ImageView) findViewById(R.id.imageView);
        view.setOnTouchListener(this);
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) 
    {
        ImageView view = (ImageView) v;
        view.setScaleType(ImageView.ScaleType.MATRIX);
        float scale;

        dumpEvent(event);
        // Handle touch events here...

        switch (event.getAction() & MotionEvent.ACTION_MASK) 
        {
            case MotionEvent.ACTION_DOWN:   // first finger down only
                                                savedMatrix.set(matrix);
                                                start.set(event.getX(), event.getY());
                                                Log.d(TAG, "mode=DRAG"); // write to LogCat
                                                mode = DRAG;
                                                break;

            case MotionEvent.ACTION_UP: // first finger lifted

            case MotionEvent.ACTION_POINTER_UP: // second finger lifted

                                                mode = NONE;
                                                Log.d(TAG, "mode=NONE");
                                                break;

            case MotionEvent.ACTION_POINTER_DOWN: // first and second finger down

                                                oldDist = spacing(event);
                                                Log.d(TAG, "oldDist=" + oldDist);
                                                if (oldDist > 5f) {
                                                    savedMatrix.set(matrix);
                                                    midPoint(mid, event);
                                                    mode = ZOOM;
                                                    Log.d(TAG, "mode=ZOOM");
                                                }
                                                break;

            case MotionEvent.ACTION_MOVE:

                                                if (mode == DRAG) 
                                                { 
                                                    matrix.set(savedMatrix);
                                                    matrix.postTranslate(event.getX() - start.x, event.getY() - start.y); // create the transformation in the matrix  of points
                                                } 
                                                else if (mode == ZOOM) 
                                                { 
                                                    // pinch zooming
                                                    float newDist = spacing(event);
                                                    Log.d(TAG, "newDist=" + newDist);
                                                    if (newDist > 5f) 
                                                    {
                                                        matrix.set(savedMatrix);
                                                        scale = newDist / oldDist; // setting the scaling of the
                                                                                    // matrix...if scale > 1 means
                                                                                    // zoom in...if scale < 1 means
                                                                                    // zoom out
                                                        matrix.postScale(scale, scale, mid.x, mid.y);
                                                    }
                                                }
                                                break;
        }

        view.setImageMatrix(matrix); // display the transformation on screen

        return true; // indicate event was handled
    }

    /*
     * --------------------------------------------------------------------------
     * Method: spacing Parameters: MotionEvent Returns: float Description:
     * checks the spacing between the two fingers on touch
     * ----------------------------------------------------
     */

    private float spacing(MotionEvent event) 
    {
        float x = event.getX(0) - event.getX(1);
        float y = event.getY(0) - event.getY(1);
        return (float) Math.sqrt(x * x + y * y);
    }

    /*
     * --------------------------------------------------------------------------
     * Method: midPoint Parameters: PointF object, MotionEvent Returns: void
     * Description: calculates the midpoint between the two fingers
     * ------------------------------------------------------------
     */

    private void midPoint(PointF point, MotionEvent event) 
    {
        float x = event.getX(0) + event.getX(1);
        float y = event.getY(0) + event.getY(1);
        point.set(x / 2, y / 2);
    }

    /** Show an event in the LogCat view, for debugging */
    private void dumpEvent(MotionEvent event) 
    {
        String names[] = { "DOWN", "UP", "MOVE", "CANCEL", "OUTSIDE","POINTER_DOWN", "POINTER_UP", "7?", "8?", "9?" };
        StringBuilder sb = new StringBuilder();
        int action = event.getAction();
        int actionCode = action & MotionEvent.ACTION_MASK;
        sb.append("event ACTION_").append(names[actionCode]);

        if (actionCode == MotionEvent.ACTION_POINTER_DOWN || actionCode == MotionEvent.ACTION_POINTER_UP) 
        {
            sb.append("(pid ").append(action >> MotionEvent.ACTION_POINTER_ID_SHIFT);
            sb.append(")");
        }

        sb.append("[");
        for (int i = 0; i < event.getPointerCount(); i++) 
        {
            sb.append("#").append(i);
            sb.append("(pid ").append(event.getPointerId(i));
            sb.append(")=").append((int) event.getX(i));
            sb.append(",").append((int) event.getY(i));
            if (i + 1 < event.getPointerCount())
                sb.append(";");
        }

        sb.append("]");
        Log.d("Touch Events ---------", sb.toString());
    }
}

4
bất cứ khi nào tôi chạm vào hình ảnh, nó sẽ phóng to. tôi nên làm gì để ngăn chặn nó
Muhammad Umar

3
Tôi thực sự đánh giá cao một câu trả lời cho nhận xét ở trên. Điều tương tự cũng xảy ra với tôi. Có cách nào để ngăn nó phóng to ở lần nhấn đầu tiên không? Chính ImageViewnó được đặt thành centerFit.
Baz

29
@Baz, để tránh phóng to trong lần nhấn đầu tiên, hãy sử dụng case MotionEvent.ACTION_DOWN: // first finger down only matrix.set(view.getImageMatrix()); savedMatrix.set(matrix);Thao tác này sẽ sao chép cài đặt tỷ lệ hiện tại về ban đầumatrix
Johnny Doe

3
Làm thế nào để chúng tôi giữ hình ảnh trong màn hình? Bởi vì tôi có thể tiếp tục cuộn nó cho đến khi nó nằm ngoài tầm nhìn.
Can Canbek

14
Đối với những người sử dụng mã trên, "return FloatMath.sqrt (x * x + y * y);" thay thế nó bằng "return (float) Math.sqrt (x * x + y * y);" coz FloatMath hiện không được dùng nữa. Chúc mừng
Nagaraj Alagusudaram

97

Các triển khai khác ở đây đều có một số loại lỗ hổng. vì vậy về cơ bản tôi đã trộn chúng và nghĩ ra điều này.

Tạo một dạng xem tùy chỉnh như sau:

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

Sau đó thêm hình ảnh như sau:

ZoomableImageView touch = (ZoomableImageView)findViewById(R.id.IMAGEID);
touch.setImageBitmap(bitmap);

Thêm dạng xem như thế này trong XML:

<PACKAGE.ZoomableImageView
android:id="@+id/IMAGEID"
android:layout_width="match_parent"
android:layout_height="match_parent"/>

1
tùy thuộc vào bạn loại quy mô nào bạn thích.
Nicolas Tyler

2
Tôi không nói rằng bạn nên thay đổi kiểu scaletype thành fitXy ... Và nếu bạn thay đổi mã đó không phải lỗi của tôi mà nó không hoạt động. Tôi đã cung cấp cho bạn một giải pháp làm việc mà tôi đã sử dụng trước đây.
Nicolas Tyler

1
Tôi sẽ thêm nhận xét, nhưng nó không phức tạp lắm, saveScalelà giá trị tỷ lệ hiện tại của hình ảnh, minScalelà giá trị nhỏ nhất mà hình ảnh có thể đi được và maxScalelà giá trị lớn nhất mà hình ảnh có thể mở rộng.
Nicolas Tyler

1
Không cần sử dụng, setOnTouchListener()bạn chỉ có thể ghi đèpublic boolean onTouchEvent(MotionEvent event)
alexbirkett 23/02/16

1
Tôi đang sử dụng lớp của bạn trong một dự án kotlin. Tất cả những gì tôi phải làm là thay thế ImageView bằng ZoomableImageView của bạn trong layout xml và nó đã hoạt động hiệu quả! Cảm ơn.
Lensflare 14/09/18

26

Cách đơn giản:

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

Thêm dòng dưới đây vào build.gradle:

compile 'com.commit451:PhotoView:1.2.4'

Tốt, nhưng điều này chỉ dành cho chế độ xem hình ảnh. Cách đính kèm Lớp được mở rộng bởi View vào bộ đính kèm này. Bạn có bất kỳ ý tưởng nào,
Zia Ur Rahman

Điều này hoạt động rất tốt. Tôi đã thử các câu trả lời khác và chúng không hoạt động, hoặc không hoạt động bình thường.
Feuby

Đây là một phiên bản lỗi thời. Xem repo để biết hướng dẫn cho PhotoView mới nhất: github.com/chrisbanes/PhotoView
Ed J

Mặc dù PhotoView theo các hướng dẫn liên kết ở trên, nó không hoạt động. Câu trả lời của bạn (PhotoViewAttacher) dường như làm việc
arniotaki

13

chỉ cần sử dụng lớp này: TouchImageView


3
Tuân theo nguyên tắc cộng đồng của chúng tôi. Không cung cấp liên kết bên ngoài vì liên kết trong tương lai có thể không truy cập được. Hơn nữa, cung cấp một số đoạn mã.
Yohanes AI

13

Đây là một triển khai khác dựa trên mã được đăng bởi Nicolas Tyler.

Các lỗi sau đã được sửa:

  • Đặt minScalethành một số nhỏ hơn 1 hiện hoạt động
  • Bạn không cần sử dụng setImageBitmap()để đặt hình ảnh (ví dụ: bạn có thể sử dụngsetImageResource()
  • Tất cả các hàm tạo hiện hoạt động bình thường

Những điều sau đây, trong số những thứ khác được sắp xếp gọn gàng:

  • An OnTouchListenerkhông được sử dụng, nó không cần thiết vì lớp chỉ có thể triển khai onTouchEvent()phương thức.

  • Bài tập right = width * saveScale - width - (2 * redundantXSpace * saveScale);đã được đơn giản hóa thành right = (originalBitmapWidth * saveScale) - widthMà, theo tùy chọn của tôi, ít gây nhầm lẫn hơn nhiều.

  • Một số biến thành viên bị xóa (có thể xóa thêm trạng thái khỏi lớp này)

Nó không hoàn hảo nhưng bạn xem đây:

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:
 * /programming/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;
    }
}

Bạn đã làm rất tốt. Tôi đã sửa đổi một chút mã của bạn. Tôi đã vô hiệu hóa khả năng di chuyển hình ảnh trên X hoặc Y nếu chiều rộng hoặc chiều cao nhỏ hơn giới hạn của màn hình
roroinpho21

@ROHITPARMAR Tôi sẽ đăng một nhận xét mới với lớp của tôi.
roroinpho21

2
có cách nào để khôi phục lại tỷ lệ của hình ảnh khi nhấn ImageViewđúp?
Vishwajit Palankar

Cảm ơn! Hoạt động tốt. Nếu bạn sử dụng widget này bên trong ViewPager, một số khó khăn sẽ xuất hiện. 1) Thang điểm không được đặt lại về 1 sau khi tiến và lùi. 2) Nếu bạn cố gắng thay đổi một hình ảnh, chuyển động sẽ chậm và ngắn. Và bạn thỉnh thoảng có thể chuyển sang hình ảnh tiếp theo. Đó không phải là vấn đề của giải pháp, nhưng bạn nên nhận ra một hành vi mới.
CoolMind

Bạn đã thêm getWidth()getHeight()trong onScalephương pháp, nơi thực hiện chúng?
Mehdi Dehghani

13

Nó cũ, nhưng điều này có thể giúp ích cho người khác.

Bên dưới lớp TouchImageView hỗ trợ cả phóng to / thu nhỏ bằng cách chụm hoặc nhấn đúp

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

Cách sử dụng: Bạn có thể thay thế ImageViewbằng TouchImageView trong cả XML và java

1. Đối với 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. Đối với Java

TouchImageView imViewedImage = findViewById(R.id.imViewedImage);

Tôi bắt đầu nó với setImageURI (imageUri) và mọi hình ảnh đều xuất hiện màu đen ... Chế độ xem có đúng kích thước, chiều cao và các thuộc tính khác nhau nhưng không hiển thị bất kỳ thứ gì dù là hình ảnh nào.
SuppressWarnings ngày

@SuppressWarnings cảm ơn bạn đã thông báo rằng, tôi không chắc liệu mình đã cố gắng đặt nó theo chương trình hay chưa; cần phải nhìn lại .. và sẽ đề cập đến bạn cho bất kỳ giải pháp nào :)
Zain

12

Tôi đã cải thiện câu trả lời mà tôi nhận được từ ngăn xếp cho ZOOM hoàn hảo (hai ngón tay) / ROTATION (hai ngón tay) / DRAG (Một ngón tay) .

nhập mô tả hình ảnh ở đây

// ============================ Mã 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>

// ============================ Mã 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);
    }

}

// ======================== Chỉ cần chuyển bất kỳ chế độ xem nào bạn muốn phóng to / xoay / kéo sang phương thức viewTransformation (). Rất áp dụng cho chế độ xem văn bản Nó sẽ không tạo pixel cho văn bản.


8

Tôi đã thực hiện chế độ xem hình ảnh tùy chỉnh của riêng mình với tính năng chụm để thu phóng. Không có giới hạn / đường viền trên mã của Chirag Raval , vì vậy người dùng có thể kéo hình ảnh ra khỏi màn hình.

Đây là lớp 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);
    }


}

Đây là cách bạn có thể sử dụng nó trong hoạt động của mình:

CustomImageVIew mImageView = (CustomImageVIew)findViewById(R.id.customImageVIew1);
mImage.setBitmap(your bitmap);

Và bố cục:

<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

OK, triển khai tốt nhất cho đến nay. Vấn đề chính của tôi với việc triển khai này là ngay từ đầu, hình ảnh được hiển thị ở tỷ lệ 1: 1 và chúng tôi không thể thực hiện thu nhỏ. Ngoài ra, nó là thực hiện fav của tôi vậy, đến nay trên chủ đề này
SysHex

6

Tôi nghĩ câu trả lời của Chirag Ravals là tuyệt vời!

Điều duy nhất nó có thể được cải thiện là di chuyển tất cả mã này vào bên trong một số lớp như:

PinchZoomImageView extends ImageView {...

và thêm vào đó khởi tạo Ma trận hình ảnh ban đầu để ngăn phóng to sau lần nhấn đầu tiên:

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    matrix = new Matrix(this.getImageMatrix());
}

BTW, điều này sẽ sửa một lỗi do Muhammad Umar và Baz đề cập

PS Có giới hạn thu phóng Tối đa và Tối thiểu cũng có thể hữu ích. Ví dụ: Thu phóng tối đa là 2X và thu phóng tối thiểu là tỷ lệ ban đầu khi hình ảnh được lắp vào màn hình:

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

Vì lý do nào đó, matrix = new Matrix(this.getImageMatrix());dòng làm cho hình ảnh biến mất đối với tôi. Bạn có biết tại sao?
gta0004

Nếu bạn làm điều đó bên trong onMeasure (), ma trận sẽ chỉ nhận được giá trị chính xác theo tỷ lệ mặc định của Chế độ xem hiện tại. Và ma trận này sẽ chỉ được sử dụng sau lần tương tác tiếp theo với người dùng (ví dụ: chạm vào). Và hình ảnh bạn biến mất khi nào?
goRGon

@goRGon Xin chào, Trong ứng dụng của tôi, tôi đặt hình ảnh vừa với màn hình. Và tôi muốn phóng to ngoài kích thước màn hình đang hoạt động tốt. Và tôi cần thu nhỏ, kéo, xoay hình ảnh chỉ được thực hiện bên ngoài màn hình chứ không phải bên trong màn hình. làm ơn giúp tôi làm thế nào để làm điều đó.
Satheesh

6

Tôi đã nhận được câu trả lời hữu ích nhất từ ​​@Nicolas Tyler nhưng tôi gặp vấn đề với cách thức hoạt động của cú pháp và logic. Tôi cũng không muốn có bất kỳ không gian Alpha nào và Đại số của tôi bị gỉ! Sau 3 ngày, tôi đã tổng hợp phiên bản của riêng tôi về điều này.

Câu trả lời của tôi khác với @Nicolas Tyler như sau:

  1. Các tên biến khác nhau mà tôi thấy có ý nghĩa hơn trong việc sử dụng theo ngữ cảnh cơ bản

  2. Lớp hình ảnh Pinch-Zoom này KHÔNG hiển thị không gian alpha và sẽ cho phép bạn phóng to và thu nhỏ và vẫn không cho phép bạn xoay / quét một hình ảnh và hiển thị không gian alpha

  3. Đã thêm nhận xét sâu vào phần ma trận để giải thích những gì đang xảy ra với phép toán liên quan

  4. Lớp hình ảnh này cũng sẽ cho phép bạn chuyển vào resourceId và nó sẽ tạo ra một bitmap từ nó

  5. Các thuật toán đơn giản hơn nhiều cho cả chia tỷ lệ và dịch thuật và ít biến

  6. Thay đổi hình ảnh bên trong này sẽ khiến nó phóng to / thu nhỏ để hình ảnh mới chiếm vùng chứa chế độ xem

Bạn có thể tìm thấy một tài nguyên bổ sung tuyệt vời về Đại số tại đây: https://youtu.be/IiXB6tYtY4w?t=4m12s Video đó bao gồm cốt lõi của ma trận Vô hướng và Dịch (và sẽ giúp bạn hiểu rõ về MTRANS_X và MTRANS_Y). Nếu bạn có câu hỏi đặt ra và tôi sẽ cố gắng hết sức để trả lời (nhưng tôi KHÔNG phải là chuyên gia Đại số).

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

Ý nghĩa của "không gian alpha" là gì?
YakirNa

Nó hoạt động tuyệt vời và thực sự là một giải pháp sạch hơn nhiều so với bản gốc. Một điều bạn đã bỏ lỡ là cử chỉ tỷ lệ luôn mở rộng đến góc trên cùng bên trái của hình ảnh, thay vì ở giữa các ngón tay. Tôi sẽ thử và sửa chữa nó, vì vậy nếu bạn có bất kỳ gợi ý nào cho tôi, nó sẽ được đánh giá cao. Cảm ơn!
YakirNa

Tôi thấy rằng thay thế mMatrix.postScale(scaleFactor, scaleFactor);bằng mMatrix.postScale(scaleFactor, scaleFactor, detector.getFocusX(), detector.getFocusY());bên trong public boolean onScale(ScaleGestureDetector detector)đang thực hiện một mẹo khi bạn phóng to. Cần thêm mã để hỗ trợ thu nhỏ. nhưng hiện tại, với tôi như vậy là đủ.
YakirNa

Bất cứ ai có thể cho tôi biết làm thế nào để khởi tạo nó? Đang hoạt động mạnh. Tôi đã xóa android:srcandroid:scaleTypekhỏi tệp xml. Cách thêm hình ảnh trong thư mục "drawable" vào nó.
driftking9987

Có một số vấn đề với điều này: * Các zoom ban đầu là sai (sử dụng giải pháp có thể xảy ra scale = Math.min(scaleX, scaleY);trong adjustScale()* Các phóng to không làm theo các điểm giữa giữa ngón tay.
alexbirkett

6

Mã này hoạt động và thực hiện nhấn đúp để quay lại kích thước hình ảnh ban đầu.

Bước đầu tiên - Trong bố cục xml của bạn, hãy đặt điều này:

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

Bước thứ 2 - Tạo tệp (TouchImageView.java) với lớp TouchImageView:

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.widget.ImageView;

public class TouchImageView extends ImageView {

    Matrix matrix;

    // We can be in one of these 3 states
    static final int NONE = 0;
    static final int DRAG = 1;
    static final int ZOOM = 2;
    int mode = NONE;

    // Remember some things for zooming
    PointF last = new PointF();
    PointF start = new PointF();
    float minScale = 1f;
    float maxScale = 3f;
    float[] m;
    float redundantXSpace, redundantYSpace, origRedundantXSpace, origRedundantYSpace;

    int viewWidth, viewHeight;
    static final int CLICK = 3;
    static final float SAVE_SCALE = 1f;
    float saveScale = SAVE_SCALE;
    protected float origWidth, origHeight;
    int oldMeasuredWidth, oldMeasuredHeight;
    float origScale, bottom, origBottom, right, origRight;

    ScaleGestureDetector mScaleDetector;
    GestureDetector mGestureDetector;

    Context context;

    public TouchImageView(Context context) {
        super(context);
        sharedConstructing(context);
    }

    public TouchImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        sharedConstructing(context);
    }

    private void sharedConstructing(Context context) {
        super.setClickable(true);
        this.context = context;
        mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
        matrix = new Matrix();
        m = new float[9];
        setImageMatrix(matrix);
        setScaleType(ScaleType.MATRIX);

        setOnTouchListener(new OnTouchListener() {

            @Override
            public boolean onTouch(View v, MotionEvent event) {

                boolean onDoubleTapEvent = mGestureDetector.onTouchEvent(event);
                if (onDoubleTapEvent) {
                    // Reset Image to original scale values
                    mode = NONE;
                    bottom = origBottom;
                    right = origRight;
                    last = new PointF();
                    start = new PointF();
                    m = new float[9];
                    saveScale = SAVE_SCALE;
                    matrix = new Matrix();
                    matrix.setScale(origScale, origScale);
                    matrix.postTranslate(origRedundantXSpace, origRedundantYSpace);
                    setImageMatrix(matrix);
                    invalidate();
                    return true;
                }

                mScaleDetector.onTouchEvent(event);
                PointF curr = new PointF(event.getX(), event.getY());

                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        last.set(curr);
                        start.set(last);
                        mode = DRAG;
                        break;

                    case MotionEvent.ACTION_MOVE:
                        if (mode == DRAG) {
                            float deltaX = curr.x - last.x;
                            float deltaY = curr.y - last.y;
                            float fixTransX = getFixDragTrans(deltaX, viewWidth, origWidth * saveScale);
                            float fixTransY = getFixDragTrans(deltaY, viewHeight, origHeight * saveScale);
                            matrix.postTranslate(fixTransX, fixTransY);
                            fixTrans();
                            last.set(curr.x, curr.y);
                        }
                        break;

                    case MotionEvent.ACTION_UP:
                        mode = NONE;
                        int xDiff = (int) Math.abs(curr.x - start.x);
                        int yDiff = (int) Math.abs(curr.y - start.y);
                        if (xDiff < CLICK && yDiff < CLICK) performClick();
                        break;

                    case MotionEvent.ACTION_POINTER_UP:
                        mode = NONE;
                        break;
                }

                setImageMatrix(matrix);
                invalidate();
                return true; // indicate event was handled
            }

        });

        mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
            @Override
            public boolean onDoubleTapEvent(MotionEvent e) {
                return true;
            }
        });
    }

    public void setMaxZoom(float x) {
        maxScale = x;
    }

    private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
        @Override
        public boolean onScaleBegin(ScaleGestureDetector detector) {
            mode = ZOOM;
            return true;
        }

        @Override
        public boolean onScale(ScaleGestureDetector detector) {
            float mScaleFactor = detector.getScaleFactor();
            //float mScaleFactor = (float) Math.min(Math.max(.95f, detector.getScaleFactor()), 1.05);
            float origScale = saveScale;
            saveScale *= mScaleFactor;
            if (saveScale > maxScale) {
                saveScale = maxScale;
                mScaleFactor = maxScale / origScale;
            } else if (saveScale < minScale) {
                saveScale = minScale;
                mScaleFactor = minScale / origScale;
            }

            right = viewWidth * saveScale - viewWidth - (2 * redundantXSpace * saveScale);
            bottom = viewHeight * saveScale - viewHeight - (2 * redundantYSpace * saveScale);

            if (origWidth * saveScale <= viewWidth || origHeight * saveScale <= viewHeight)
                matrix.postScale(mScaleFactor, mScaleFactor, viewWidth / 2, viewHeight / 2);
            else
                matrix.postScale(mScaleFactor, mScaleFactor, detector.getFocusX(), detector.getFocusY());

            fixTrans();
            return true;
        }
    }

    void fixTrans() {
        matrix.getValues(m);
        float transX = m[Matrix.MTRANS_X];
        float transY = m[Matrix.MTRANS_Y];

        float fixTransX = getFixTrans(transX, viewWidth, origWidth * saveScale);
        float fixTransY = getFixTrans(transY, viewHeight, origHeight * saveScale);

        if (fixTransX != 0 || fixTransY != 0)
            matrix.postTranslate(fixTransX, fixTransY);
    }

    float getFixTrans(float trans, float viewSize, float contentSize) {
        float minTrans, maxTrans;

        if (contentSize <= viewSize) {
            minTrans = 0;
            maxTrans = viewSize - contentSize;
        } else {
            minTrans = viewSize - contentSize;
            maxTrans = 0;
        }

        if (trans < minTrans)
            return -trans + minTrans;
        if (trans > maxTrans)
            return -trans + maxTrans;
        return 0;
    }

    float getFixDragTrans(float delta, float viewSize, float contentSize) {
        if (contentSize <= viewSize) {
            return 0;
        }
        return delta;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        viewWidth = MeasureSpec.getSize(widthMeasureSpec);
        viewHeight = MeasureSpec.getSize(heightMeasureSpec);

        //
        // Rescales image on rotation
        //
        if (oldMeasuredHeight == viewWidth && oldMeasuredHeight == viewHeight || viewWidth == 0 || viewHeight == 0) return;

        oldMeasuredHeight = viewHeight;
        oldMeasuredWidth = viewWidth;

        if (saveScale == 1) {
            // Fit to screen.
            float scale;
            int bmWidth,bmHeight;

            Bitmap bm = BitmapFactory.decodeResource(context.getResources(), R.mipmap.myinfolinks_splash);
            bmWidth = bm.getWidth();
            bmHeight = bm.getHeight();

            int  w = bmWidth;
            int  h = bmHeight;
            viewWidth = resolveSize(w, widthMeasureSpec);
            viewHeight = resolveSize(h, heightMeasureSpec);

            float scaleX = (float) viewWidth / (float) bmWidth;
            float scaleY = (float) viewHeight / (float) bmHeight;
            scale = Math.min(scaleX, scaleY);
            matrix.setScale(scale, scale);
            saveScale = SAVE_SCALE;
            origScale = scale;

            // Center the image
            redundantYSpace = (float) viewHeight - (scale * (float) bmHeight);
            redundantXSpace = (float) viewWidth - (scale * (float) bmWidth);
            redundantYSpace /= (float) 2;
            redundantXSpace /= (float) 2;

            origRedundantXSpace = redundantXSpace;
            origRedundantYSpace = redundantYSpace;

            matrix.postTranslate(redundantXSpace, redundantYSpace);

            origWidth = viewWidth - 2 * redundantXSpace;
            origHeight = viewHeight - 2 * redundantYSpace;

            right = viewWidth * saveScale - viewWidth - (2 * redundantXSpace * saveScale);
            bottom = viewHeight * saveScale - viewHeight - (2 * redundantYSpace * saveScale);
            origRight = right;
            origBottom = bottom;

            setImageMatrix(matrix);
        }
        fixTrans();
    }
}

Và cuối cùng, thực hiện cuộc gọi trong hoạt động chính của bạn:

TouchImageView imgDisplay = (TouchImageView) messageView.findViewById(R.id.id_myImage);
imgDisplay.setMaxZoom(2f);
imgDisplay.setImageResource(R.drawable.myImage);

Tôi đã thấy rất nhiều mã và sau khi điều chỉnh, nó hoạt động. Thưởng thức!


Để thực hiện tốt hơn, hãy thay đổi dòng này: Bitmap bm = BitmapFactory.decodeResource (context.getResources (), R.mipmap.myinfolinks_splash); cho cái này: ImageView img = (ImageView) findViewById (R.id.action_infolinks_splash);
jmtsilva69

Và bạn không cần điều này (nó đã được đặt trong bố cục xml): imgDisplay.setImageResource (R.mipmap.myinfolinks_splash);
jmtsilva69

Skizo- this: ImageView img = (ImageView) findViewById (R.id.action_infolinks_splash)
jmtsilva69

Skizo- this: ImageView img = (ImageView) findViewById (R.id.action_infolinks_splash) nó dùng để lấy chiều rộng và chiều cao hình ảnh theo lập trình. Hôm qua, tôi đã cải tiến mã để bán lại tỷ lệ và tôi chỉ sử dụng hình ảnh jpg xxhdpi (1026px x 770px), như vậy tôi tạo ra ứng dụng nhỏ hơn và hình ảnh điều chỉnh thành công cho tất cả kích thước màn hình.
jmtsilva69

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


3

Hãy thử những cách sau:

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

3

Tôi cần một cái gì đó tương tự, nhưng cần khả năng nhận các kích thước dễ dàng và cũng có thể kéo / thả. Tôi dựa trên câu trả lời mà @Nicolas Tyler đưa ra và sửa đổi nó từ đó.

Các tính năng là phóng to / thu nhỏ, nhấn và giữ để rung / kéo / thả được đánh dấu.

Để sử dụng nó, hãy thêm lớp CustomZoomView này vào dự án của bạn.

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

}
}

... sau đó thêm cái này vào hoạt động của bạn

CustomZoomView customImageView = (CustomZoomView) findViewById(R.id.customZoomView);
customImageView.setBitmap(yourBitmap);

... và điều này theo quan điểm của bạn trong xml.

<your.package.name.CustomZoomView
   android:id="@+id/customZoomView"
   android:layout_width="fill_parent"
   android:layout_height="fill_parent"
   android:longClickable="true"/>

... và thêm cái này vào tệp kê khai của bạn

<uses-permission android:name="android.permission.VIBRATE"/>

3

Đây là giải pháp của tôi, nó dựa trên giải pháp của @ 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 .
}

Nếu điều này không hiệu quả, hãy thử mở rộng android.support.v7.widget.AppCompatImageView.
Alejandro Cumpa

Xin chào, Bạn có thể cho tôi biết cách sử dụng nó trong Main Class không? Tôi đã nghĩ ra điều này, Bạn có thể cho tôi biết tiếp theo nên làm gì không? ZoomableImageView touch = (ZoomableImageView) findViewById (R.id.image1);
Muhammad Noman

3

Bước 1: Đầu tiên bạn thêm các phần phụ thuộc vào tệp build.gradle (Module: app).

dependencies {

     implementation 'com.jsibbold:zoomage:1.2.0'

    }

Bước 2: Tiếp theo tạo một lớp

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;

}

Bước 3: Tiếp theo tạo một tệp xml bố cục

gment_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>

OutPut: -

Hình ảnh bình thường

Phóng to Hình ảnh

Phóng to Hình ảnh


2

Phương pháp gọi hộp thoại Giới thiệu & hỗ trợ

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

1

Tôi biết là hơi muộn cho câu trả lời này, nhưng tôi hy vọng nó sẽ giúp ích cho ai đó.

Tôi đang tìm kiếm thứ tương tự (Thu phóng bằng cách sử dụng chụm và kéo hình ảnh) và tôi tìm thấy liên kết Blog nhà phát triển Android này .

Hoạt động hoàn hảo. Không có hiện vật hoặc những gì đã từng. Nó sử dụng ScaleGestureDetector.


0

Liên kết 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);
}

0

Chỉ cần thay đổi ACTION_MOVE_EVENT trong Chirag Raval Answer để đặt 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);
                }


0

Tôi nghĩ tại sao bạn muốn phóng to và thu nhỏ chế độ xem hình ảnh là do chế độ xem ảnh của bạn nhỏ và việc phóng ảnh ở đó sẽ không cho ảnh ra khỏi chế độ xem ảnh. Thay vào đó, hình ảnh bắt đầu biến mất khỏi ranh giới khi phóng to. Vì vậy, để hình ảnh thoát ra khỏi hình ảnh trong khi chúng tôi phóng to là điều bạn muốn, tôi đoán vậy.

Vì vậy, có hai thủ thuật (theo tôi) để đạt được điều này-

  1. Thay đổi các thông số bố cục của chế độ xem hình ảnh để bao phủ toàn bộ chế độ xem ngoài cùng hoặc nhóm chế độ xem trong thời gian chạy trong khi chúng tôi chuẩn bị phóng to hình ảnh.
  2. Tạo chế độ xem Hình ảnh mở rộng hoặc Chế độ xem Hình ảnh Toàn bộ (chiều cao và chiều rộng = Chế độ xem Ngoài cùng hoặc Nhóm Chế độ xem) trong tệp xml và đặt chế độ hiển thị của nó thành biến mất. Khi chúng ta chuẩn bị phóng to hình ảnh, hãy tải hình ảnh từ Chế độ xem hình ảnh nhỏ vào Chế độ xem hình ảnh đầy đủ, ánh xạ hình ảnh trong FullImgView sang hình ảnh trong Chế độ xem nhỏ và làm cho hình ảnh đó hiển thị.

Thủ thuật số 1 không hoạt động khi Chế độ xem hình ảnh được lồng rất nhiều bên trong các chế độ xem khác (như trong chế độ xem trình tái chế lồng nhau)

Lừa không. 2 công trình luôn :-)

Đây là cách thực hiện thủ thuật số 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);
    }

}

LƯU Ý: - Không đặt OnClickListener thành mfullImgView trước khi đặt onTouchListener cho nó. Cài đặt sẽ cho phép fullImageView (nếu nó hiển thị) đánh cắp sự kiện chạm khi đặt ngón tay thứ hai xuống sau khi nhấc ngón tay thứ hai lên vì chúng tôi muốn cho phép smallImgView thực hiện tất cả các sự kiện chạm cho đến khi tất cả các ngón tay được nhấc lên lần đầu tiên thời gian.


-2

Tôi đang sử dụng cái này nó đang hoạt động hoàn hảo.

<your.packagename.MyZoomableImageViewTouch
        android:id="@+id/mediaImage"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:scaleType="matrix"/>

Lớp MyZoomableImageViewTouch của tôi ở bên dưới:

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

ví dụ của bạn có mã không đầy đủ, rất nhiều lỗi và thiếu lớp ImageViewTouch.
Däñish Shärmà
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.