Збільшити і зменшити масштаб зображення Android ImageView


114

Я хочу збільшити та зменшити масштаб зображення Android ImageView. Я спробував більшість зразків, але в усіх з них зображення у самому ImageView отримує збільшення та зменшення масштабу, тоді як я хочу збільшувати та зменшувати зображення. Я хочу збільшити ширину та висоту ImageView під час збільшення та зменшити ширину та висоту ImageView під час зменшення масштабу. Як я цього досягти?


пройти через це: stackoverflow.com/questions/9846914 / ...
ess.crazy

1
Google наводив приклад для перегляду масштабування / зменшення: developer.android.com/training/animation/zoom.html
Кай

1
перевірити цю відповідь її дивовижно іone line of code
Basheer AL-MOMANI

Цей приклад від Android досить надійний, покрокові інструкції та вихідний код надані. developer.android.com/training/animation/zoom.html
Аль-Катірі Халід

Скористайтеся перевагою github.com/rahulkapoor1/ZommableLoadingImageView
Рахул

Відповіді:


25

Зробіть два заняття з java

Клас масштабування

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.view.KeyEvent;
import android.view.View;
import android.widget.Button;
import android.widget.ImageButton;

public class Zoom extends View {

    private Drawable image;
    ImageButton img,img1;
    private int zoomControler=20;

    public Zoom(Context context){
            super(context);

            image=context.getResources().getDrawable(R.drawable.j);
            //image=context.getResources().getDrawable(R.drawable.icon);

            setFocusable(true);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        //here u can control the width and height of the images........ this line is very important
        image.setBounds((getWidth()/2)-zoomControler, (getHeight()/2)-zoomControler, (getWidth()/2)+zoomControler, (getHeight()/2)+zoomControler);
        image.draw(canvas);
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {

            if(keyCode==KeyEvent.KEYCODE_DPAD_UP){
                    // zoom in
                    zoomControler+=10;
            }
            if(keyCode==KeyEvent.KEYCODE_DPAD_DOWN){
                    // zoom out
                    zoomControler-=10;
            }
            if(zoomControler<10){
                    zoomControler=10;
            }

            invalidate();
            return true;
    }
}

зробити другий клас

import android.app.Activity;
import android.os.Bundle;

public class Zoomexample extends Activity {
   /** Called when the activity is first created. */

   @Override
   public void onCreate(Bundle icicle) {
       super.onCreate(icicle);
       setContentView(new Zoom(this));
   }
}

я отримав помилку в ... image = context.getResources (). getDravable (R.dravable.j); Я копіюю зображення в папку, що перетягується. Я перейменував зображення на j .. Я отримав j неможливо вирішити або це не поле ..
chinna_82

@ chinna_82, зображення має бути j.png, і ви повинні розмістити його в папці Dravable. Потім оновіть проект і помилки не повинно бути
KhalidTaha

1
як я можу збільшити масштаб поза viewpager, означає весь екран?
доктор медицини Халі

211

Дотримуйтесь нижченаведеного класу, який використовується для збільшення та зменшення масштабу для 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
щоразу, коли я натискаю на зображення, воно збільшує. що мені робити, щоб зупинити це
Мухаммед Умар

3
Я дуже вдячний відповіді на коментар вище. Те саме відбувається і зі мною. Чи є якийсь спосіб запобігти збільшенню масштабу у перший кран? ImageViewСам встановлюються в centerFit.
Баз

29
@Baz, щоб уникнути збільшення масштабу при першому використанні крана case MotionEvent.ACTION_DOWN: // first finger down only matrix.set(view.getImageMatrix()); savedMatrix.set(matrix); Це скопіює поточні параметри масштабування до початковихmatrix
Johnny Doe

3
Як ми зберігаємо зображення на екрані? Тому що я можу продовжувати прокручувати його до тих пір, поки його дуже не видно.
Can Canbek

14
Для тих, хто використовує вищевказаний код, "поверніть FloatMath.sqrt (x * x + y * y);" замініть його на "return (float) Math.sqrt (x * x + y * y);" coz FloatMath зараз застарілий. Ура
Нагарадж Алагусударам

97

Інші реалізації тут мають певний недолік. тому я в основному змішав їх і придумав це.

Створіть спеціальний вигляд таким:

ZoomableImageView.java:

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

public class ZoomableImageView extends ImageView
{
    Matrix matrix = new Matrix();

    static final int NONE = 0;
    static final int DRAG = 1;
    static final int ZOOM = 2;
    static final int CLICK = 3;
    int mode = NONE;

    PointF last = new PointF();
    PointF start = new PointF();
    float minScale = 1f;
    float maxScale = 4f;
    float[] m;

    float redundantXSpace, redundantYSpace;
    float width, height;
    float saveScale = 1f;
    float right, bottom, origWidth, origHeight, bmWidth, bmHeight;

    ScaleGestureDetector mScaleDetector;
    Context context;

    public ZoomableImageView(Context context, AttributeSet attr)
    {
        super(context, attr);
        super.setClickable(true);
        this.context = context;
        mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
        matrix.setTranslate(1f, 1f);
        m = new float[9];
        setImageMatrix(matrix);
        setScaleType(ScaleType.MATRIX);

        setOnTouchListener(new OnTouchListener()
        {

            @Override
            public boolean onTouch(View v, MotionEvent event)
            {
                mScaleDetector.onTouchEvent(event);

                matrix.getValues(m);
                float x = m[Matrix.MTRANS_X];
                float y = m[Matrix.MTRANS_Y];
                PointF curr = new PointF(event.getX(), event.getY());

                switch (event.getAction())
                {
                    //when one finger is touching
                    //set the mode to DRAG
                    case MotionEvent.ACTION_DOWN:
                        last.set(event.getX(), event.getY());
                        start.set(last);
                        mode = DRAG;
                        break;
                    //when two fingers are touching
                    //set the mode to ZOOM
                    case MotionEvent.ACTION_POINTER_DOWN:
                        last.set(event.getX(), event.getY());
                        start.set(last);
                        mode = ZOOM;
                        break;
                    //when a finger moves
                    //If mode is applicable move image
                    case MotionEvent.ACTION_MOVE:
                        //if the mode is ZOOM or
                        //if the mode is DRAG and already zoomed
                        if (mode == ZOOM || (mode == DRAG && saveScale > minScale))
                        {
                            float deltaX = curr.x - last.x;// x difference
                            float deltaY = curr.y - last.y;// y difference
                            float scaleWidth = Math.round(origWidth * saveScale);// width after applying current scale
                            float scaleHeight = Math.round(origHeight * saveScale);// height after applying current scale
                            //if scaleWidth is smaller than the views width
                            //in other words if the image width fits in the view
                            //limit left and right movement
                            if (scaleWidth < width)
                            {
                                deltaX = 0;
                                if (y + deltaY > 0)
                                    deltaY = -y;
                                else if (y + deltaY < -bottom)
                                    deltaY = -(y + bottom);
                            }
                            //if scaleHeight is smaller than the views height
                            //in other words if the image height fits in the view
                            //limit up and down movement
                            else if (scaleHeight < height)
                            {
                                deltaY = 0;
                                if (x + deltaX > 0)
                                    deltaX = -x;
                                else if (x + deltaX < -right)
                                    deltaX = -(x + right);
                            }
                            //if the image doesnt fit in the width or height
                            //limit both up and down and left and right
                            else
                            {
                                if (x + deltaX > 0)
                                    deltaX = -x;
                                else if (x + deltaX < -right)
                                    deltaX = -(x + right);

                                if (y + deltaY > 0)
                                    deltaY = -y;
                                else if (y + deltaY < -bottom)
                                    deltaY = -(y + bottom);
                            }
                            //move the image with the matrix
                            matrix.postTranslate(deltaX, deltaY);
                            //set the last touch location to the current
                            last.set(curr.x, curr.y);
                        }
                        break;
                    //first finger is lifted
                    case MotionEvent.ACTION_UP:
                        mode = NONE;
                        int xDiff = (int) Math.abs(curr.x - start.x);
                        int yDiff = (int) Math.abs(curr.y - start.y);
                        if (xDiff < CLICK && yDiff < CLICK)
                            performClick();
                        break;
                    // second finger is lifted
                    case MotionEvent.ACTION_POINTER_UP:
                        mode = NONE;
                        break;
                }
                setImageMatrix(matrix);
                invalidate();
                return true;
            }

        });
    }

    @Override
    public void setImageBitmap(Bitmap bm)
    {
        super.setImageBitmap(bm);
        bmWidth = bm.getWidth();
        bmHeight = bm.getHeight();
    }

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

    private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener
    {

        @Override
        public boolean onScaleBegin(ScaleGestureDetector detector)
        {
            mode = ZOOM;
            return true;
        }

        @Override
        public boolean onScale(ScaleGestureDetector detector)
        {
            float mScaleFactor = detector.getScaleFactor();
            float origScale = saveScale;
            saveScale *= mScaleFactor;
            if (saveScale > maxScale)
            {
                saveScale = maxScale;
                mScaleFactor = maxScale / origScale;
            }
            else if (saveScale < minScale)
            {
                saveScale = minScale;
                mScaleFactor = minScale / origScale;
            }
            right = width * saveScale - width - (2 * redundantXSpace * saveScale);
            bottom = height * saveScale - height - (2 * redundantYSpace * saveScale);
            if (origWidth * saveScale <= width || origHeight * saveScale <= height)
            {
                matrix.postScale(mScaleFactor, mScaleFactor, width / 2, height / 2);
                if (mScaleFactor < 1)
                {
                    matrix.getValues(m);
                    float x = m[Matrix.MTRANS_X];
                    float y = m[Matrix.MTRANS_Y];
                    if (mScaleFactor < 1)
                    {
                        if (Math.round(origWidth * saveScale) < width)
                        {
                            if (y < -bottom)
                                matrix.postTranslate(0, -(y + bottom));
                            else if (y > 0)
                                matrix.postTranslate(0, -y);
                        }
                        else
                        {
                            if (x < -right)
                                matrix.postTranslate(-(x + right), 0);
                            else if (x > 0)
                                matrix.postTranslate(-x, 0);
                        }
                    }
                }
            }
            else
            {
                matrix.postScale(mScaleFactor, mScaleFactor, detector.getFocusX(), detector.getFocusY());
                matrix.getValues(m);
                float x = m[Matrix.MTRANS_X];
                float y = m[Matrix.MTRANS_Y];
                if (mScaleFactor < 1) {
                    if (x < -right)
                        matrix.postTranslate(-(x + right), 0);
                    else if (x > 0)
                        matrix.postTranslate(-x, 0);
                    if (y < -bottom)
                        matrix.postTranslate(0, -(y + bottom));
                    else if (y > 0)
                        matrix.postTranslate(0, -y);
                }
            }
            return true;
        }
    }

    @Override
    protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec)
    {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        width = MeasureSpec.getSize(widthMeasureSpec);
        height = MeasureSpec.getSize(heightMeasureSpec);
        //Fit to screen.
        float scale;
        float scaleX =  width / bmWidth;
        float scaleY = height / bmHeight;
        scale = Math.min(scaleX, scaleY);
        matrix.setScale(scale, scale);
        setImageMatrix(matrix);
        saveScale = 1f;

        // Center the image
        redundantYSpace = height - (scale * bmHeight) ;
        redundantXSpace = width - (scale * bmWidth);
        redundantYSpace /= 2;
        redundantXSpace /= 2;

        matrix.postTranslate(redundantXSpace, redundantYSpace);

        origWidth = width - 2 * redundantXSpace;
        origHeight = height - 2 * redundantYSpace;
        right = width * saveScale - width - (2 * redundantXSpace * saveScale);
        bottom = height * saveScale - height - (2 * redundantYSpace * saveScale);
        setImageMatrix(matrix);
    }
}

Потім додайте зображення так:

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

Додайте такий вигляд у XML:

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

1
від вас залежить, який саме ви скажете.
Ніколя Тайлер

2
Я не казав, що ви повинні змінити скелет на fitXy ... І якщо ви зміните код, це не моя вина, що він не працює. Я надав вам робоче рішення, яким я користувався раніше.
Ніколя Тайлер

1
Додам коментарі, але це не так вже й складно saveScale- це поточне значення масштабу зображення, minScaleвоно є найменшим, яке воно може отримати, і maxScaleє найбільше, яке зображення може масштабувати.
Ніколя Тайлер

1
Не потрібно користуватися, setOnTouchListener()ви можете просто перекритиpublic boolean onTouchEvent(MotionEvent event)
alexbirkett

1
Я використовую ваш клас у проекті kotlin. Все, що мені потрібно було зробити, це замінити ImageView на ваш ZoomableImageView у макеті xml, і це вийшло з коробки! Дякую.
Lensflare

26

Простий спосіб:

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

Додати рядок у build.gradle :

compile 'com.commit451:PhotoView:1.2.4'

Добре, але це лише для перегляду зображень. Як долучити клас, розширений View, до цього вкладення. У вас є ідея,
Зія Ур Рахман

Це працює дуже добре. Я доглядав інші відповіді, і вони не працювали, або не працювали належним чином.
Feuby

Це застаріла версія. Дивіться репо для вказівок щодо останнього PhotoView: github.com/chrisbanes/PhotoView
Ed J

Хоча PhotoView відповідно до наведених вище посилань інструкцій, він не працює. Ваша відповідь (PhotoViewAttacher), здається, працює
arniotaki

13

просто використовуйте цей клас: TouchImageView


3
Дотримуйтесь наших правил спільноти. Не надайте зовнішні посилання, оскільки в майбутньому посилання можуть бути недоступними. Крім того, дайте код фрагменту.
Йохан AI

13

Це ще одна реалізація на основі коду, опублікованого Ніколасом Тайлером.

Виправлені такі помилки:

  • Налаштування minScale числа менше 1 зараз працює
  • Не потрібно використовувати setImageBitmap() для встановлення зображення (ви можете використовувати, наприклад,setImageResource()
  • Усі конструктори зараз працюють належним чином

Серед інших пристосовано такі речі:

  • An OnTouchListenerне використовується, це не потрібно, оскільки клас може просто реалізувати onTouchEvent()метод.

  • Присвоєння right = width * saveScale - width - (2 * redundantXSpace * saveScale);було спрощено до параметра right = (originalBitmapWidth * saveScale) - widthЩо, на мій вибір, є набагато менш заплутаним.

  • Деякі змінні учасника видалено (більше цього стану, можливо, буде видалено з цього класу)

Це не ідеально, але ось що:

import android.content.Context;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.widget.ImageView;

/**
 * Created by alex on 23/02/16.
 * Based on code posted by Nicolas Tyler here:
 * /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;
    }
}

Чудова робота. Я трохи змінив ваш код. Я відключив можливість переміщення зображення на X або Y, якщо ширина або висота менше меж дисплея
roroinpho21

@ROHITPARMAR Я опублікую новий коментар зі своїм класом.
roroinpho21

2
чи є спосіб відновити масштабування зображення при ImageViewподвійному натисканні?
Vishwajit Palankar

Дякую! Добре працює. Якщо ви використовуєте цей віджет всередині ViewPager, з’являються деякі труднощі. 1) Шкала не скидається до 1 після переміщення вперед та назад. 2) Якщо ви намагаєтеся змістити зображення, рух відбувається повільно і коротко. І ви можете час від часу переходити до наступної картини. Це не проблема рішення, але вам слід усвідомити нову поведінку.
CoolMind

Ви додали getWidth()і getHeight()в onScaleметоді, де їх реалізація?
Мехді Дехгані

13

Це старе, але це може допомогти комусь іншому.

Нижче клас TouchImageView підтримує збільшення та зменшення масштабу або при натисканні, або подвійному натисканні

import android.content.Context;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.widget.ImageView;

public class TouchImageView extends ImageView implements GestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener {

    Matrix matrix;

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

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

    int viewWidth, viewHeight;
    static final int CLICK = 3;
    float saveScale = 1f;
    protected float origWidth, origHeight;
    int oldMeasuredWidth, oldMeasuredHeight;

    ScaleGestureDetector mScaleDetector;

    Context context;

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

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

    GestureDetector mGestureDetector;

    private void sharedConstructing(Context context) {
        super.setClickable(true);
        this.context = context;
        mGestureDetector = new GestureDetector(context, this);
        mGestureDetector.setOnDoubleTapListener(this);

        mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
        matrix = new Matrix();
        m = new float[9];
        setImageMatrix(matrix);
        setScaleType(ScaleType.MATRIX);

        setOnTouchListener(new OnTouchListener() {

            @Override
            public boolean onTouch(View v, MotionEvent event) {
                mScaleDetector.onTouchEvent(event);
                mGestureDetector.onTouchEvent(event);

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

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

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

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

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

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

        });
    }

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

    @Override
    public boolean onSingleTapConfirmed(MotionEvent e) {
        return false;
    }

    @Override
    public boolean onDoubleTap(MotionEvent e) {
        // Double tap is detected
        Log.i("MAIN_TAG", "Double tap detected");
        float origScale = saveScale;
        float mScaleFactor;

        if (saveScale == maxScale) {
            saveScale = minScale;
            mScaleFactor = minScale / origScale;
        } else {
            saveScale = maxScale;
            mScaleFactor = maxScale / origScale;
        }

        matrix.postScale(mScaleFactor, mScaleFactor, viewWidth / 2,
                viewHeight / 2);

        fixTrans();
        return false;
    }

    @Override
    public boolean onDoubleTapEvent(MotionEvent e) {
        return false;
    }

    @Override
    public boolean onDown(MotionEvent e) {
        return false;
    }

    @Override
    public void onShowPress(MotionEvent e) {

    }

    @Override
    public boolean onSingleTapUp(MotionEvent e) {
        return false;
    }

    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
        return false;
    }

    @Override
    public void onLongPress(MotionEvent e) {

    }

    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
        return false;
    }

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

        @Override
        public boolean onScale(ScaleGestureDetector detector) {
            float mScaleFactor = detector.getScaleFactor();
            float origScale = saveScale;
            saveScale *= mScaleFactor;
            if (saveScale > maxScale) {
                saveScale = maxScale;
                mScaleFactor = maxScale / origScale;
            } else if (saveScale < minScale) {
                saveScale = minScale;
                mScaleFactor = minScale / origScale;
            }

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

            fixTrans();
            return true;
        }
    }

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

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

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

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

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

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

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

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

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

        if (saveScale == 1) {
            // Fit to screen.
            float scale;

            Drawable drawable = getDrawable();
            if (drawable == null || drawable.getIntrinsicWidth() == 0
                    || drawable.getIntrinsicHeight() == 0)
                return;
            int bmWidth = drawable.getIntrinsicWidth();
            int bmHeight = drawable.getIntrinsicHeight();

            Log.d("bmSize", "bmWidth: " + bmWidth + " bmHeight : " + bmHeight);

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

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

            matrix.postTranslate(redundantXSpace, redundantYSpace);

            origWidth = viewWidth - 2 * redundantXSpace;
            origHeight = viewHeight - 2 * redundantYSpace;
            setImageMatrix(matrix);
        }
        fixTrans();
    }
}

Використання: Ви можете замінити ImageViewTouchImageView як у XML, так і у Java

1. Для XML

<?xml version="1.0" encoding="utf-8"?>
<com.example.android.myapp.TouchImageView 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/imViewedImage"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:clickable="true"
    android:focusable="true" />

2. Для Java

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

Я починаю це з setImageURI (imageUri), і кожне зображення виглядає чорним ... Перегляд отримує правильний розмір, висоту та різні атрибути, але нічого не показує, незалежно від зображення.
SuppressWarnings

@SuppressWarnings спасибі за повідомлення про це, я не впевнений, чи намагався я встановити це програмно; потрібно озирнутися назад .. і згадаю вас про будь-яке подолання :)
Заїн

12

Я вдосконалив відповідь, яку я отримав зі стека для бездоганної ZOOM (два пальці) / ROTATION (два пальці) / DRAG (Single finger) .

введіть тут опис зображення

// ============================ XML-код ===================

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.flochat.imageviewzoomforstack.MainActivity">

    <ImageView
        android:id="@+id/imageview_trash"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/trash" />

</LinearLayout>

// ============================ Код Java =================== ========

public class MainActivity extends AppCompatActivity {

    ImageView photoview2;
    float[] lastEvent = null;
    float d = 0f;
    float newRot = 0f;
    private boolean isZoomAndRotate;
    private boolean isOutSide;
    private static final int NONE = 0;
    private static final int DRAG = 1;
    private static final int ZOOM = 2;
    private int mode = NONE;
    private PointF start = new PointF();
    private PointF mid = new PointF();
    float oldDist = 1f;
    private float xCoOrdinate, yCoOrdinate;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);

        setContentView(R.layout.activity_main);

        photoview2 = findViewById(R.id.imageview_trash);

        photoview2.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                ImageView view = (ImageView) v;
                view.bringToFront();
                viewTransformation(view, event);
                return true;
            }
        });
    }


    private void viewTransformation(View view, MotionEvent event) {
        switch (event.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN:
            xCoOrdinate = view.getX() - event.getRawX();
            yCoOrdinate = view.getY() - event.getRawY();

                start.set(event.getX(), event.getY());
                isOutSide = false;
                mode = DRAG;
                lastEvent = null;
                break;
            case MotionEvent.ACTION_POINTER_DOWN:
                oldDist = spacing(event);
                if (oldDist > 10f) {
                    midPoint(mid, event);
                    mode = ZOOM;
                }

                lastEvent = new float[4];
                lastEvent[0] = event.getX(0);
                lastEvent[1] = event.getX(1);
                lastEvent[2] = event.getY(0);
                lastEvent[3] = event.getY(1);
                d = rotation(event);
                break;
            case MotionEvent.ACTION_UP:
                isZoomAndRotate = false;
                if (mode == DRAG) {
                    float x = event.getX();
                    float y = event.getY();
                }
            case MotionEvent.ACTION_OUTSIDE:
                isOutSide = true;
                mode = NONE;
                lastEvent = null;
            case MotionEvent.ACTION_POINTER_UP:
                mode = NONE;
                lastEvent = null;
                break;
            case MotionEvent.ACTION_MOVE:
                if (!isOutSide) {
                    if (mode == DRAG) {
                        isZoomAndRotate = false;
                        view.animate().x(event.getRawX() + xCoOrdinate).y(event.getRawY() + yCoOrdinate).setDuration(0).start();
                    }
                    if (mode == ZOOM && event.getPointerCount() == 2) {
                        float newDist1 = spacing(event);
                        if (newDist1 > 10f) {
                            float scale = newDist1 / oldDist * view.getScaleX();
                            view.setScaleX(scale);
                            view.setScaleY(scale);
                        }
                        if (lastEvent != null) {
                            newRot = rotation(event);
                            view.setRotation((float) (view.getRotation() + (newRot - d)));
                        }
                    }
                }
                break;
        }
    }

    private float rotation(MotionEvent event) {
        double delta_x = (event.getX(0) - event.getX(1));
        double delta_y = (event.getY(0) - event.getY(1));
        double radians = Math.atan2(delta_y, delta_x);
        return (float) Math.toDegrees(radians);
    }

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

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

}

// ========================= Просто передайте будь-який вид, який ви хочете збільшити / повернути / перетягнути, щоб переглянути методTransformation (). Дуже підходить для збільшення масштабу тексту. Він не буде пікселізувати текст.


8

Я зробив власний власний перегляд зображень із щіпкою для збільшення. У Chirag Raval немає обмежень / меж коду , тому користувач може перетягувати зображення з екрана.

Ось клас CustomImageView:

    public class CustomImageVIew extends ImageView implements OnTouchListener {


    private Matrix matrix = new Matrix();
    private Matrix savedMatrix = new Matrix();

    static final int NONE = 0;
    static final int DRAG = 1;
    static final int ZOOM = 2;

    private int mode = NONE;

    private PointF mStartPoint = new PointF();
    private PointF mMiddlePoint = new PointF();
    private Point mBitmapMiddlePoint = new Point();

    private float oldDist = 1f;
    private float matrixValues[] = {0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f};
    private float scale;
    private float oldEventX = 0;
    private float oldEventY = 0;
    private float oldStartPointX = 0;
    private float oldStartPointY = 0;
    private int mViewWidth = -1;
    private int mViewHeight = -1;
    private int mBitmapWidth = -1;
    private int mBitmapHeight = -1;
    private boolean mDraggable = false;


    public CustomImageVIew(Context context) {
        this(context, null, 0);
    }

    public CustomImageVIew(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CustomImageVIew(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        this.setOnTouchListener(this);
    }

    @Override
    public void onSizeChanged (int w, int h, int oldw, int oldh){
        super.onSizeChanged(w, h, oldw, oldh);
        mViewWidth = w;
        mViewHeight = h;
    }

    public void setBitmap(Bitmap bitmap){
        if(bitmap != null){
            setImageBitmap(bitmap);

            mBitmapWidth = bitmap.getWidth();
            mBitmapHeight = bitmap.getHeight();
            mBitmapMiddlePoint.x = (mViewWidth / 2) - (mBitmapWidth /  2);
            mBitmapMiddlePoint.y = (mViewHeight / 2) - (mBitmapHeight / 2);

            matrix.postTranslate(mBitmapMiddlePoint.x, mBitmapMiddlePoint.y);
            this.setImageMatrix(matrix);
        }
    }

    @Override
    public boolean onTouch(View v, MotionEvent event){
        switch (event.getAction() & MotionEvent.ACTION_MASK) {
        case MotionEvent.ACTION_DOWN:
            savedMatrix.set(matrix);
            mStartPoint.set(event.getX(), event.getY());
            mode = DRAG;
            break;
        case MotionEvent.ACTION_POINTER_DOWN:
            oldDist = spacing(event);
            if(oldDist > 10f){
                savedMatrix.set(matrix);
                midPoint(mMiddlePoint, event);
                mode = ZOOM;
            }
            break;
        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_POINTER_UP:
            mode = NONE;
            break;
        case MotionEvent.ACTION_MOVE:
            if(mode == DRAG){
                drag(event);
            } else if(mode == ZOOM){
                zoom(event);
            } 
            break;
        }

        return true;
    }



   public void drag(MotionEvent event){
       matrix.getValues(matrixValues);

       float left = matrixValues[2];
       float top = matrixValues[5];
       float bottom = (top + (matrixValues[0] * mBitmapHeight)) - mViewHeight;
       float right = (left + (matrixValues[0] * mBitmapWidth)) -mViewWidth;

       float eventX = event.getX();
       float eventY = event.getY();
       float spacingX = eventX - mStartPoint.x;
       float spacingY = eventY - mStartPoint.y;
       float newPositionLeft = (left  < 0 ? spacingX : spacingX * -1) + left;
       float newPositionRight = (spacingX) + right;
       float newPositionTop = (top  < 0 ? spacingY : spacingY * -1) + top;
       float newPositionBottom = (spacingY) + bottom;
       boolean x = true;
       boolean y = true;

       if(newPositionRight < 0.0f || newPositionLeft > 0.0f){
           if(newPositionRight < 0.0f && newPositionLeft > 0.0f){
               x = false;
           } else{
               eventX = oldEventX;
               mStartPoint.x = oldStartPointX;
           }
       }
       if(newPositionBottom < 0.0f || newPositionTop > 0.0f){
           if(newPositionBottom < 0.0f && newPositionTop > 0.0f){
               y = false;
           } else{
               eventY = oldEventY;
               mStartPoint.y = oldStartPointY;
           }
       }

       if(mDraggable){
           matrix.set(savedMatrix);
           matrix.postTranslate(x? eventX - mStartPoint.x : 0, y? eventY - mStartPoint.y : 0);
           this.setImageMatrix(matrix);
           if(x)oldEventX = eventX;
           if(y)oldEventY = eventY;
           if(x)oldStartPointX = mStartPoint.x;
           if(y)oldStartPointY = mStartPoint.y;
       }

   }

   public void zoom(MotionEvent event){
       matrix.getValues(matrixValues);

       float newDist = spacing(event);
       float bitmapWidth = matrixValues[0] * mBitmapWidth;
       float bimtapHeight = matrixValues[0] * mBitmapHeight;
       boolean in = newDist > oldDist;

       if(!in && matrixValues[0] < 1){
           return;
       }
       if(bitmapWidth > mViewWidth || bimtapHeight > mViewHeight){
           mDraggable = true;
       } else{
           mDraggable = false;
       }

       float midX = (mViewWidth / 2);
       float midY = (mViewHeight / 2);

       matrix.set(savedMatrix);
       scale = newDist / oldDist;
       matrix.postScale(scale, scale, bitmapWidth > mViewWidth ? mMiddlePoint.x : midX, bimtapHeight > mViewHeight ? mMiddlePoint.y : midY); 

       this.setImageMatrix(matrix);


   }





    /** Determine the space between the first two fingers */
    private float spacing(MotionEvent event) {
        float x = event.getX(0) - event.getX(1);
        float y = event.getY(0) - event.getY(1);

        return (float)Math.sqrt(x * x + y * y);
    }

    /** Calculate the mid point of the first two fingers */
    private void midPoint(PointF point, MotionEvent event) {
        float x = event.getX(0) + event.getX(1);
        float y = event.getY(0) + event.getY(1);
        point.set(x / 2, y / 2);
    }


}

Ось як це можна використовувати у своїй діяльності:

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

І макет:

<your.package.name.CustomImageVIew
        android:id="@+id/customImageVIew1"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_marginBottom="15dp"
        android:layout_marginLeft="15dp"
        android:layout_marginRight="15dp"
        android:layout_marginTop="15dp"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true" 
        android:scaleType="matrix"/> // important

Добре, найкраща реалізація поки що. Моя головна проблема з цією реалізацією полягає в тому, що після отримання зображення зображення відображається у співвідношенні 1: 1, і ми не можемо виконати зменшення масштабу. Крім цього, це моє фаворитне реалізація поки що на цій темі
SysHex

6

Я думаю, що відповідь Chirag Ravals чудова!

Єдине, що можна було б покращити - це переміщення всього цього коду всередині якогось класу, як-от:

PinchZoomImageView extends ImageView {...

і додавши туди початкову ініціалізацію матриці зображень, щоб запобігти масштабуванню після першого натискання:

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

До речі, це виправить помилку, про яку згадували Мухаммед Умар та Баз

PS, що мають обмеження максимального та мінімального масштабування, також можуть бути корисними. Напр. Максимальний зум - 2 рази, а мінімальне збільшення - оригінальна шкала, коли зображення встановлено на екран:

static final int MAX_SCALE_FACTOR = 2;

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);

    // Getting initial Image matrix
    mViewMatrix = new Matrix(this.getImageMatrix());
    mMinScaleMatrix = new Matrix(mViewMatrix);
    float initialScale = getMatrixScale(mViewMatrix);


    if (initialScale < 1.0f) // Image is bigger than screen
        mMaxScale = MAX_SCALE_FACTOR;
    else
        mMaxScale = MAX_SCALE_FACTOR * initialScale;

    mMinScale = getMatrixScale(mMinScaleMatrix);
}


@Override
public boolean onTouch(View v, MotionEvent event) {
    ImageView view = (ImageView) v;
    // We set scale only after onMeasure was called and automatically fit image to screen
    if(!mWasScaleTypeSet) {
        view.setScaleType(ImageView.ScaleType.MATRIX);
        mWasScaleTypeSet = true;
    }

    float scale;

    dumpEvent(event);

    switch (event.getAction() & MotionEvent.ACTION_MASK) {
    case MotionEvent.ACTION_DOWN: // first finger down only
        mCurSavedMatrix.set(mViewMatrix);
        start.set(event.getX(), event.getY());
        mCurrentMode = DRAG;
        break;

    case MotionEvent.ACTION_UP: // first finger lifted
    case MotionEvent.ACTION_POINTER_UP: // second finger lifted
        mCurrentMode = NONE;

        float resScale = getMatrixScale(mViewMatrix);

        if (resScale > mMaxScale) {
            downscaleMatrix(resScale, mViewMatrix);
        } else if (resScale < mMinScale)
            mViewMatrix = new Matrix(mMinScaleMatrix);
        else if ((resScale - mMinScale) < 0.1f) // Don't allow user to drag picture outside in case of FIT TO WINDOW zoom
            mViewMatrix = new Matrix(mMinScaleMatrix);
        else
            break;

        break;

    case MotionEvent.ACTION_POINTER_DOWN: // first and second finger down
        mOldDist = spacing(event);
        Helper.LOGD(TAG, "oldDist=" + mOldDist);
        if (mOldDist > 5f) {
            mCurSavedMatrix.set(mViewMatrix);
            midPoint(mCurMidPoint, event);
            mCurrentMode = ZOOM;
            Helper.LOGD(TAG, "mode=ZOOM");
        }
        break;

    case MotionEvent.ACTION_MOVE:
        if (mCurrentMode == DRAG) {
            mViewMatrix.set(mCurSavedMatrix);
            mViewMatrix.postTranslate(event.getX() - start.x, event.getY() - start.y); // create the transformation in the matrix  of points
        } else if (mCurrentMode == ZOOM) {
            // pinch zooming
            float newDist = spacing(event);
            Helper.LOGD(TAG, "newDist=" + newDist);
            if (newDist > 1.f) {
                mViewMatrix.set(mCurSavedMatrix);
                scale = newDist / mOldDist; // setting the scaling of the
                                            // matrix...if scale > 1 means
                                            // zoom in...if scale < 1 means
                                            // zoom out
                mViewMatrix.postScale(scale, scale, mCurMidPoint.x, mCurMidPoint.y);
            }
        }
        break;
    }

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

    return true; // indicate event was handled
}


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////// PRIVATE SECTION ///////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// These matrices will be used to scale points of the image
private Matrix mViewMatrix = new Matrix();
private Matrix mCurSavedMatrix = new Matrix();
// These PointF objects are used to record the point(s) the user is touching
private PointF start = new PointF();
private PointF mCurMidPoint = new PointF();
private float mOldDist = 1f;

private Matrix mMinScaleMatrix;
private float mMinScale;
private float mMaxScale;
float[] mTmpValues = new float[9];
private boolean mWasScaleTypeSet;


/**
 * Returns scale factor of the Matrix
 * @param matrix
 * @return
 */
private float getMatrixScale(Matrix matrix) {
    matrix.getValues(mTmpValues);
    return mTmpValues[Matrix.MSCALE_X];
}

/**
 * Downscales matrix with the scale to maximum allowed scale factor, but the same translations
 * @param scale
 * @param dist
 */
private void downscaleMatrix(float scale, Matrix dist) {
    float resScale = mMaxScale / scale;
    dist.postScale(resScale, resScale, mCurMidPoint.x, mCurMidPoint.y);
}

Чомусь matrix = new Matrix(this.getImageMatrix());рядок змушує образ зникати для мене. Ти знаєш чому?
gta0004

Якщо зробити це всередині onMeasure (), матриця просто отримає правильне значення відповідно до поточної шкали View zoom за замовчуванням. І ця матриця буде використана лише після наступної взаємодії з користувачем (натисніть, наприклад). А коли образ зник?
goRGon

@goRGon Привіт, у своїй програмі я встановив зображення із розміщенням на екрані. І я хочу збільшити масштаб, крім розміру екрана, який працює чудово. І мені потрібно зменшити масштаб, перетягнути, обернути зображення, яке робиться тільки поза екраном, а не всередині екрана. pls допоможіть мені, як це зробити.
Сатеєш

6

Я отримав найкориснішу відповідь від @Nicolas Tyler, але у мене виникли проблеми з тим, як працювали синтаксис та логіка. Я також не хотів ніякого альфа-простору, і моя Алгебра була іржавою! Через 3 дні я склав свою власну версію цього.

Моя відповідь відрізняється від @Nicolas Tyler таким:

  1. Різні імена змінних, які я знайшов, мали більше сенсу в основі контекстного використання

  2. Цей клас зображень Pinch-Zoom НЕ показує альфа-простір і дозволить вам збільшувати та зменшувати масштаби, а також не дозволить вам перевертати / під панорамувати зображення та розкривати альфа-пробіл

  3. До розділу матриці додано глибокі коментарі, щоб пояснити, що відбувається із залученою математикою

  4. Цей клас зображень також дозволить вам пройти в resourceId, і він створить з нього растрову карту

  5. Набагато простіші алгоритми як для масштабування, так і для перекладу та кількох змінних

  6. Якщо змінити зображення в межах цього, це призведе до його збільшення / зменшення, щоб нове зображення зайняло контейнер перегляду

Чудове оновлення ресурсів щодо алгебри можна знайти тут: https://youtu.be/IiXB6tYtY4w?t=4m12s Це відео охоплює ядро ​​матриць Scalar та Translation (і допоможе вам зрозуміти матеріали MTRANS_X та MTRANS_Y). Якщо у вас є питання, запитайте, і я зроблю все можливе, щоб відповісти (але я НЕ експерт з алгебри).

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

public class iImage extends ImageView
{
    static final int NONE_MODE = 0;
    static final int DRAG_MODE = 1;
    static final int ZOOM_MODE = 2;
    int _mode = NONE_MODE;

    Matrix _matrix = new Matrix();
    PointF _previousPoint = new PointF();
    PointF _startPoint = new PointF();
    float _currentScale = 1f;
    float _minScale = 1f;
    float _maxScale = 3f;
    float[] _arrayOf9Floats;
    float _bitmapWidth, _bitmapHeight,_displayWidth, _displayHeight;
    ScaleGestureDetector _scaleDetector;
    Context _context;

    public iImage(Context context)
    {
        super(context);
        super.setClickable(true);
        _context = context;
        _scaleDetector = new ScaleGestureDetector(context, new ScaleListener());
        _arrayOf9Floats = new float[9];
        setScaleType(ScaleType.MATRIX);
        setOnTouchListener(new OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                return handleTouch(v, event);
            }
        });
    }

    private boolean handleTouch(View v, MotionEvent event)
    {
        _scaleDetector.onTouchEvent(event);
        //Contrary to how this line looks, the matrix is not setting the values from the arrayOf9Floats, but rather taking the
        //matrix values and assigning them into the arrayOf9Floats. I extremely dislike this syntax and I think
        //it should have been written as _arrayOf9Floats = _matrix.getValues() but that's Android for you!!!
        _matrix.getValues(_arrayOf9Floats);

        //Look at https://youtu.be/IiXB6tYtY4w?t=4m12s , it shows scale, rotate, and translate matrices
        //If you look at the translate matrix, you'll see that the 3rd and 6th values are the values which represent x and y translations respectively
        //this corresponds to the 2nd and 5th values in the array and hence why the MTRANS_X and MTRANS_Y have the constants 2 and 5 respectively
        float xTranslate = _arrayOf9Floats[Matrix.MTRANS_X];
        float yTranslate = _arrayOf9Floats[Matrix.MTRANS_Y];
        PointF currentEventPoint = new PointF(event.getX(), event.getY());
        switch (event.getAction())
        {
            //First finger down only
            case MotionEvent.ACTION_DOWN:
                _previousPoint.set(event.getX(), event.getY());
                _startPoint.set(_previousPoint);
                _mode = DRAG_MODE;
                break;
            //Second finger down
            case MotionEvent.ACTION_POINTER_DOWN:
                _previousPoint.set(event.getX(), event.getY());
                _startPoint.set(_previousPoint);
                _mode = ZOOM_MODE;
                break;
            case MotionEvent.ACTION_MOVE:
                if (_mode == ZOOM_MODE || _mode == DRAG_MODE )
                {
                    float deltaX = currentEventPoint.x - _previousPoint.x;
                    float deltaY = currentEventPoint.y - _previousPoint.y;
                    //In matrix terms, going right is + and going left is +
                    //Moving the image right past 0 means it will show alpha space on the left so we dont want that
                    //Keep in mind this is a TOP LEFT pivot point, so we dont want the top left to be past 0 lest we have alpha space
                    if(xTranslate + deltaX > 0)
                    {
                        //get absolute of how much into the negative we would have gone
                        float excessDeltaX = Math.abs(xTranslate + deltaX);
                        //take that excess away from deltaX so X wont got less than 0 after the translation
                        deltaX = deltaX - excessDeltaX;
                    }

                    //Going left we dont want the negative value to be less than the negative width of the sprite, lest we get alpha space on the right
                    //The width is going to be the width of the bitmap * scale and we want the - of it because we are checking for left movement
                    //We also need to account for the width of the DISPLAY CONTAINER (i.e. _displayWidth) so that gets subtracted
                    //i.e. we want the max scroll width value
                    float maxScrollableWidth = _bitmapWidth * _currentScale - _displayWidth;
                    if(xTranslate + deltaX < -maxScrollableWidth)
                    {
                        //this forces the max possible translate to always match the - of maxScrollableWidth
                        deltaX = -maxScrollableWidth - xTranslate;
                    }

                    //repeat for Y
                    if(yTranslate + deltaY > 0)
                    {
                        float excessDeltaY = Math.abs(yTranslate + deltaY);
                        deltaY = deltaY - excessDeltaY;
                    }

                    float maxScrollableHeight = _bitmapHeight * _currentScale - _displayWidth;
                    if(yTranslate + deltaY < -maxScrollableHeight)
                    {
                        //this forces the max possible translate to always match the - of maxScrollableWidth
                        deltaY = -maxScrollableHeight - yTranslate;
                    }

                    _matrix.postTranslate(deltaX, deltaY);
                    _matrix.getValues(_arrayOf9Floats);
                    //System.out.println(_matrix);

                    _previousPoint.set(currentEventPoint.x, currentEventPoint.y);
                }
                break;
            case MotionEvent.ACTION_POINTER_UP:
                _mode = NONE_MODE;
                break;
        }
        setImageMatrix(_matrix);
        invalidate();
        return true;
    }

    @Override
    public void setImageBitmap(Bitmap bm)
    {
        super.setImageBitmap(bm);
        _bitmapWidth = bm.getWidth();
        _bitmapHeight = bm.getHeight();
        invalidate();
    }

    @Override
    public void setImageResource(int resid)
    {
        Bitmap bitmapImage = BitmapFactory.decodeResource(_context.getResources(), resid);
        setImageBitmap(bitmapImage);
    }

    private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener
    {

        @Override
        public boolean onScaleBegin(ScaleGestureDetector detector)
        {
            _mode = ZOOM_MODE;
            return true;
        }

        @Override
        public boolean onScale(ScaleGestureDetector detector)
        {
            float scaleFactor = detector.getScaleFactor();
            float originalScale = _currentScale;
            _currentScale *= scaleFactor;
            //Zoom in too much
            if (_currentScale > _maxScale) {
                _currentScale = _maxScale;
                scaleFactor = _maxScale / originalScale;
            }//Zoom out too much
            else if (_currentScale < _minScale) {
                _currentScale = _minScale;
                scaleFactor = _minScale / originalScale;
            }
           _matrix.postScale(scaleFactor,scaleFactor);

            return true;
        }
    }

    @Override
    protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec)
    {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        _displayWidth = MeasureSpec.getSize(widthMeasureSpec);
        _displayHeight = MeasureSpec.getSize(heightMeasureSpec);
        adjustScale();
    }

    private void adjustScale()
    {
        //Fit to display bounds with NO alpha space
        float scale;
        float scaleX =  _displayWidth / _bitmapWidth;
        float scaleY = _displayHeight / _bitmapHeight;
        scale = Math.max(scaleX, scaleY);
        _matrix.setScale(scale, scale);
        setImageMatrix(_matrix);
        _currentScale = scale;
        _minScale = scale;
    }

    public void setMaxZoom(float maxZoom){_maxScale = maxZoom;}
    public void setMinZoom(float minZoom) {_minScale = minZoom;}
}

Що означає "альфа-простір"?
YakirNa

Це працює чудово і справді є набагато чистішим рішенням, ніж оригінал. Одне, що ви пропустили, - це те, що жест масштабу завжди наближається до лівого верхнього кута зображення, а не між пальцями. Я спробую це виправити, тому якщо у вас є підказки для мене, це буде дуже вдячно. Дякую!
YakirNa

Я виявив, що заміна mMatrix.postScale(scaleFactor, scaleFactor);на mMatrix.postScale(scaleFactor, scaleFactor, detector.getFocusX(), detector.getFocusY());внутрішню public boolean onScale(ScaleGestureDetector detector)робить трюк, коли ви збільшуєте масштаб. Більше коду потрібно для підтримки зменшення масштабу. але наразі мені цього достатньо.
YakirNa

Хтось може сказати мені, як ініціалізувати це? У майнактичності. Я видалив android:srcі android:scaleTypeз файлу xml Як додати до нього зображення, що знаходяться у папці, що «малюється».
driftking9987

Є деякі проблеми з цим: * Початковим масштабом неправильно (використання Можливого рішення scale = Math.min(scaleX, scaleY);в adjustScale()* зумірованія не слід за точкою в середині між пальцями.
alexbirkett

6

Цей код працює і реалізує подвійне торкання, щоб повернутися до початкового розміру зображення.

1-й крок - у ваш xml макет помістіть це:

<com.****.*****.TouchImageView
    android:id="@+id/action_infolinks_splash"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:src="@mipmap/myinfolinks_splash"
    android:layout_gravity="center"
    android:gravity="center"
    android:scaleType="fitCenter"
    android:contentDescription="@string/aboutSupport_description_image"/>

2-й крок - Створіть файл (TouchImageView.java) за допомогою класу TouchImageView:

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

public class TouchImageView extends ImageView {

    Matrix matrix;

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

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

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

    ScaleGestureDetector mScaleDetector;
    GestureDetector mGestureDetector;

    Context context;

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

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

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

        setOnTouchListener(new OnTouchListener() {

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

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

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

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

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

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

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

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

        });

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

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

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

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

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

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

            fixTrans();
            return true;
        }
    }

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

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

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

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

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

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

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

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

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

        oldMeasuredHeight = viewHeight;
        oldMeasuredWidth = viewWidth;

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

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

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

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

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

            origRedundantXSpace = redundantXSpace;
            origRedundantYSpace = redundantYSpace;

            matrix.postTranslate(redundantXSpace, redundantYSpace);

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

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

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

І нарешті, зателефонуйте в основну діяльність:

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

Я побачив багато коду, і після моїх налаштувань він працює. Насолоджуйтесь!


Для кращого виконання змініть цей рядок: Bitmap bm = BitmapFactory.decodeResource (context.getResources (), R.mipmap.myinfolinks_splash); для цього: ImageView img = (ImageView) findViewById (R.id.action_infolinks_splash);
jmtsilva69

І вам це не потрібно (це вже встановлено в макеті 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) - це для програмного отримання зображення по ширині та висоті. Вчора я вдосконалював код для масштабування, і я використовую лише зображення xxhdpi jpg (1026px x 770px), як це я роблю менший додаток і зображення успішно коригую для всіх розмірів екрана.
jmtsilva69

У xml: <***. ****. AndroidI 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

Спробуйте наступне:

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

Мені потрібно було щось подібне, але потрібна була можливість легко отримувати розміри, а також перетягувати / опускати. Я ґрунтував це на відповіді @Nicolas Тайлер дав та змінив її звідти.

Особливості - прищепне збільшення / зменшення, довге натискання, щоб вібрація / виділене перетягування / падіння.

Для його використання додайте цей клас CustomZoomView до свого проекту.

public class CustomZoomView extends View implements View.OnTouchListener, View.OnLongClickListener{


private Paint mPaint;

Vibrator v;

static final int NONE = 0;
static final int DRAG = 1;
static final int ZOOM = 2;
static final int MOVE = 3;

private int mode = NONE;

Rect src;
Rect mTempDst = new Rect();
Rect dst = new Rect();

Bitmap mBitmap;

private int mBitmapWidth = -1;
private int mBitmapHeight = -1;

private PointF mStartPoint = new PointF();
private PointF mMiddlePoint = new PointF();
private PointF mStartDragPoint = new PointF();
private PointF mMovePoint = new PointF();

private float oldDist = 1f;
private float scale;
private float oldEventX = 0;
private float oldEventY = 0;
private float oldStartPointX = 0;
private float oldStartPointY = 0;
private int mViewWidth = -1;
private int mViewHeight = -1;

private boolean mDraggable = false;


public CustomZoomView(Context context) {
    this(context, null, 0);

}

public CustomZoomView(Context context, AttributeSet attrs) {
    this(context, attrs, 0);
}

public CustomZoomView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    this.setOnTouchListener(this);
    this.setOnLongClickListener(this);
    v = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
    mPaint = new Paint();
    mPaint.setColorFilter(new PorterDuffColorFilter(Color.argb(100,255,255,255), PorterDuff.Mode.SRC_IN));
}

@Override
public void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    mViewWidth = w;
    mViewHeight = h;
}

public void setBitmap(Bitmap bitmap) {
    if (bitmap != null) {

        src = new Rect();
        src.left = 0;
        src.top = 0;
        src.right = bitmap.getWidth();
        src.bottom = bitmap.getHeight();
        mBitmap = bitmap;

        mBitmapWidth = bitmap.getWidth() * 1;
        mBitmapHeight = bitmap.getHeight() * 1;

        dst = new Rect();
        dst.left = (mViewWidth / 2) - (mBitmapWidth / 2);
        dst.top = (mViewHeight / 2) - (mBitmapHeight / 2);
        dst.right = (mViewWidth / 2) + (mBitmapWidth / 2);
        dst.bottom = (mViewHeight / 2) + (mBitmapHeight / 2);

    }
}


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

    switch (event.getAction() & MotionEvent.ACTION_MASK) {
        case MotionEvent.ACTION_DOWN:
            mStartPoint.set(event.getX(), event.getY());
            mStartDragPoint.set(event.getX(), event.getY());
            mTempDst.set(dst.left, dst.top, dst.right, dst.bottom);
            mode = DRAG;
            break;
        case MotionEvent.ACTION_POINTER_DOWN:
            oldDist = spacing(event);
            if (oldDist > 10f) {
                midPoint(mMiddlePoint, event);
                mode = ZOOM;
            }
            break;
        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_POINTER_UP:
            if (mode == ZOOM) {
                mBitmapWidth = dst.right - dst.left;
                mBitmapHeight = dst.bottom - dst.top;
            }
            mode = NONE;
            break;
        case MotionEvent.ACTION_MOVE:
            if (mode == DRAG) {
                mMovePoint.x = event.getX();
                mMovePoint.y = event.getY();
                drag(event);
            } else if (mode == ZOOM) {
                zoom(event);
            } else if (mode == MOVE) {
                move(event);
            }
            break;
    }

    return false;
}

public void move(MotionEvent event) {

    int xChange = (int) (event.getX() - mStartPoint.x);
    int yChange = (int) (event.getY() - mStartPoint.y);

    dst.left = mTempDst.left + (xChange);
    dst.top = mTempDst.top + (yChange);

    dst.right = mTempDst.right + (xChange);
    dst.bottom = mTempDst.bottom + (yChange);

    invalidate();
}


public void drag(MotionEvent event) {

    float eventX = event.getX();
    float eventY = event.getY();
    float spacingX = eventX - mStartDragPoint.x;
    float spacingY = eventY - mStartDragPoint.y;
    float newPositionLeft = (dst.left < 0 ? spacingX : spacingX * -1) + dst.left;
    float newPositionRight = (spacingX) + dst.right;
    float newPositionTop = (dst.top < 0 ? spacingY : spacingY * -1) + dst.top;
    float newPositionBottom = (spacingY) + dst.bottom;
    boolean x = true;
    boolean y = true;

    if (newPositionRight < 0.0f || newPositionLeft > 0.0f) {
        if (newPositionRight < 0.0f && newPositionLeft > 0.0f) {
            x = false;
        } else {
            eventX = oldEventX;
            mStartDragPoint.x = oldStartPointX;
        }
    }
    if (newPositionBottom < 0.0f || newPositionTop > 0.0f) {
        if (newPositionBottom < 0.0f && newPositionTop > 0.0f) {
            y = false;
        } else {
            eventY = oldEventY;
            mStartDragPoint.y = oldStartPointY;
        }
    }

    if (mDraggable) {
        if (x) oldEventX = eventX;
        if (y) oldEventY = eventY;
        if (x) oldStartPointX = mStartDragPoint.x;
        if (y) oldStartPointY = mStartDragPoint.y;
    }

}

public void zoom(MotionEvent event) {
    float newDist = spacing(event);
    boolean in = newDist > oldDist;

    if (!in && scale < .01f) {
        return;
    }

    scale = newDist / oldDist;

    int xChange = (int) ((mBitmapWidth * scale) / 2);
    int yChange = (int) ((mBitmapHeight * scale) / 2);

    if (xChange > 10 && yChange > 10) { //ADDED THIS TO KEEP IT FROM GOING INVERSE

    int xMidPoint = ((dst.right - dst.left) / 2) + dst.left;
    int yMidPoint = ((dst.bottom - dst.top) / 2) + dst.top;

    dst.left = (int) (float) (xMidPoint - xChange);
    dst.top = (int) (float) (yMidPoint - yChange);

    dst.right = (int) (float) (xMidPoint + xChange);
    dst.bottom = (int) (float) (yMidPoint + yChange);

    }

    invalidate();

}


/**
 * Determine the space between the first two fingers
 */
private float spacing(MotionEvent event) {
    float x = event.getX(0) - event.getX(1);
    float y = event.getY(0) - event.getY(1);

    return (float) Math.sqrt(x * x + y * y);
}

/**
 * Calculate the mid point of the first two fingers
 */
private void midPoint(PointF point, MotionEvent event) {
    float x = event.getX(0) + event.getX(1);
    float y = event.getY(0) + event.getY(1);
    point.set(x / 2, y / 2);
}


@Override
public boolean onLongClick(View view) {


    if (mode == DRAG) {
        if ((mStartPoint.x > dst.left && mStartPoint.x < dst.right) && (mStartPoint.y < dst.bottom && mStartPoint.y > dst.top)
                && (mMovePoint.x > dst.left && mMovePoint.x < dst.right) && (mMovePoint.y < dst.bottom && mMovePoint.y > dst.top)) {
            mode = MOVE;
            v.vibrate(500);
        }
    }
    return true;
}

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    if (mode == MOVE) {
        canvas.drawBitmap(mBitmap, src, dst, null);
        canvas.drawBitmap(mBitmap, src, dst, mPaint);
    } else {
        canvas.drawBitmap(mBitmap, src, dst, null);
    }

}
}

... потім додайте це до своєї діяльності

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

... і це, на ваш погляд, у xml.

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

... і додайте це до свого маніфесту

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

3

Ось моє рішення, воно засноване на рішенні @ alexbirkett.

public class ZoomImageView extends ImageView {

// region . Static fields .

static final int NONE = 0;
static final int DRAG = 1;
static final int ZOOM = 2;
static final int CLICK = 3;

// endregion . Static fields .

// region . Fields .

private int mode = NONE;

private Matrix mMatrix = new Matrix();

private PointF mLastTouch = new PointF();
private PointF mStartTouch = new PointF();
private float minScale = 0.5f;
private float maxScale = 4f;
private float[] mCriticPoints;

private float mScale = 1f;
private float mRight;
private float mBottom;
private float mOriginalBitmapWidth;
private float mOriginalBitmapHeight;

private ScaleGestureDetector mScaleDetector;

//endregion . Fields .

// region . Ctor .
public ZoomImageView(Context context) {
    super(context);
    init(context);
}

public ZoomImageView(Context context, AttributeSet attrs) {
    super(context, attrs);
    init(context);
}

public ZoomImageView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    init(context);
}

// endregion . Ctor .

// region . Overrider .

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    int bmHeight = getBmHeight();
    int bmWidth = getBmWidth();

    float width = getMeasuredWidth();
    float height = getMeasuredHeight();
    float scale = 1;

    // If image is bigger then display fit it to screen.
    if (width < bmWidth || height < bmHeight) {
        scale = width > height ? height / bmHeight : width / bmWidth;
    }

    mMatrix.setScale(scale, scale);
    mScale = 1f;

    mOriginalBitmapWidth = scale * bmWidth;
    mOriginalBitmapHeight = scale * bmHeight;

    // Center the image
    float redundantYSpace = (height - mOriginalBitmapHeight);
    float redundantXSpace = (width - mOriginalBitmapWidth);

    mMatrix.postTranslate(redundantXSpace / 2, redundantYSpace / 2);

    setImageMatrix(mMatrix);
}

@Override
public boolean onTouchEvent(MotionEvent event) {
    mScaleDetector.onTouchEvent(event);

    mMatrix.getValues(mCriticPoints);
    float translateX = mCriticPoints[Matrix.MTRANS_X];
    float trnslateY = mCriticPoints[Matrix.MTRANS_Y];
    PointF currentPoint = new PointF(event.getX(), event.getY());

    switch (event.getAction()) {
        //when one finger is touching
        //set the mode to DRAG
        case MotionEvent.ACTION_DOWN:
            mLastTouch.set(event.getX(), event.getY());
            mStartTouch.set(mLastTouch);
            mode = DRAG;
            break;
        //when two fingers are touching
        //set the mode to ZOOM
        case MotionEvent.ACTION_POINTER_DOWN:
            mLastTouch.set(event.getX(), event.getY());
            mStartTouch.set(mLastTouch);
            mode = ZOOM;
            break;
        //when a finger moves
        //If mode is applicable move image
        case MotionEvent.ACTION_MOVE:

            //if the mode is ZOOM or
            //if the mode is DRAG and already zoomed
            if (mode == ZOOM || (mode == DRAG && mScale > minScale)) {

                // region . Move  image.

                float deltaX = currentPoint.x - mLastTouch.x;// x difference
                float deltaY = currentPoint.y - mLastTouch.y;// y difference
                float scaleWidth = Math.round(mOriginalBitmapWidth * mScale);// width after applying current scale
                float scaleHeight = Math.round(mOriginalBitmapHeight * mScale);// height after applying current scale

                // Move image to lef or right if its width is bigger than display width
                if (scaleWidth > getWidth()) {
                    if (translateX + deltaX > 0) {
                        deltaX = -translateX;
                    } else if (translateX + deltaX < -mRight) {
                        deltaX = -(translateX + mRight);
                    }
                } else {
                    deltaX = 0;
                }
                // Move image to up or bottom if its height is bigger than display height
                if (scaleHeight > getHeight()) {
                    if (trnslateY + deltaY > 0) {
                        deltaY = -trnslateY;
                    } else if (trnslateY + deltaY < -mBottom) {
                        deltaY = -(trnslateY + mBottom);
                    }
                } else {
                    deltaY = 0;
                }

                //move the image with the matrix
                mMatrix.postTranslate(deltaX, deltaY);
                //set the last touch location to the current
                mLastTouch.set(currentPoint.x, currentPoint.y);

                // endregion . Move image .
            }
            break;
        //first finger is lifted
        case MotionEvent.ACTION_UP:
            mode = NONE;
            int xDiff = (int) Math.abs(currentPoint.x - mStartTouch.x);
            int yDiff = (int) Math.abs(currentPoint.y - mStartTouch.y);
            if (xDiff < CLICK && yDiff < CLICK)
                performClick();
            break;
        // second finger is lifted
        case MotionEvent.ACTION_POINTER_UP:
            mode = NONE;
            break;
    }
    setImageMatrix(mMatrix);
    invalidate();
    return true;
}

//endregion . Overrides .

// region . Privates .

private void init(Context context) {
    super.setClickable(true);
    mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
    mCriticPoints = new float[9];
    setImageMatrix(mMatrix);
    setScaleType(ScaleType.MATRIX);
}

private int getBmWidth() {
    Drawable drawable = getDrawable();
    if (drawable != null) {
        return drawable.getIntrinsicWidth();
    }
    return 0;
}

private int getBmHeight() {
    Drawable drawable = getDrawable();
    if (drawable != null) {
        return drawable.getIntrinsicHeight();
    }
    return 0;
}

//endregion . Privates .

// region . Internal classes .

private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {

    @Override
    public boolean onScaleBegin(ScaleGestureDetector detector) {
        mode = ZOOM;
        return true;
    }

    @Override
    public boolean onScale(ScaleGestureDetector detector) {
        float scaleFactor = detector.getScaleFactor();
        float newScale = mScale * scaleFactor;
        if (newScale < maxScale && newScale > minScale) {
            mScale = newScale;
            float width = getWidth();
            float height = getHeight();
            mRight = (mOriginalBitmapWidth * mScale) - width;
            mBottom = (mOriginalBitmapHeight * mScale) - height;

            float scaledBitmapWidth = mOriginalBitmapWidth * mScale;
            float scaledBitmapHeight = mOriginalBitmapHeight * mScale;

            if (scaledBitmapWidth <= width || scaledBitmapHeight <= height) {
                mMatrix.postScale(scaleFactor, scaleFactor, width / 2, height / 2);
            } else {
                mMatrix.postScale(scaleFactor, scaleFactor, detector.getFocusX(), detector.getFocusY());
            }
        }
        return true;
    }
}

// endregion . Internal classes .
}

Якщо це не працює, спробуйте розширити android.support.v7.widget.AppCompatImageView.
Алехандро Кумпа

Привіт, Ви можете мені сказати, як це використовувати в Main Class? Я придумав це, Ви можете мені сказати, що має бути далі? ZoomableImageView touch = (ZoomableImageView) findViewById (R.id.image1);
Мухаммед Номан

3

Крок 1: Спочатку ви додаєте залежності у файл build.gradle (Модуль: додаток).

dependencies {

     implementation 'com.jsibbold:zoomage:1.2.0'

    }

Крок 2: Далі створіть клас

ImageFullScreenFragment.java

public class ImageFullScreenFragment{

   private ZoomageView ImageZoomageView;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View view = null;

      try {
         view = inflater.inflate(R.layout.fragment_image_full_screen, container, false);
            ImageZoomageView = view.findViewById(R.id.imageViewImageFullScreen);
            ImageZoomageView.setImageResource(R.drawable.image);

         } catch (Exception e) {
             e.printStackTrace();
         }
    return view;

}

Крок 3: Далі створіть файл формату xml

fragment_image_full_screen.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="8dp"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <com.jsibbold.zoomage.ZoomageView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:zoomage_restrictBounds="false"
        app:zoomage_animateOnReset="true"
        app:zoomage_autoResetMode="UNDER"
        app:zoomage_autoCenter="true"
        app:zoomage_zoomable="true"
        app:zoomage_translatable="true"
        app:zoomage_minScale="0.6"
        app:zoomage_maxScale="8"
        android:id="@+id/imageViewImageFullScreen"
        />

</RelativeLayout>

Вихід: -

Нормальне зображення

Збільшити зображення

Збільшити зображення


2

Метод виклику діалогового вікна About & Support

 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

Я знаю, що на цю відповідь трохи пізно, але сподіваюся, що це комусь допоможе.

Я шукав те саме (Збільшити за допомогою прищіпки та перетягувати зображення), і знайшов це посилання на блог розробників Android .

Працює ідеально. Жодних артефактів чи ще чого. Він використовує ScaleGestureDetector.


0

Посилання 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

Просто зміна ACTION_MOVE_EVENT в Чираг Рава Відповідь встановити ZOOM_IN LIMIT

float[] values = new float[9]; matrix.getValues(values);
                //0.37047964 is limit for zoom in
                if(values[Matrix.MSCALE_X]>0.37047964) {
                    matrix.set(savedMatrix);
                    matrix.postScale(scale, scale, mid.x, mid.y);
                    view.setImageMatrix(matrix);
                }else if (scale>1){
                    matrix.set(savedMatrix);
                    matrix.postScale(scale, scale, mid.x, mid.y);
                    view.setImageMatrix(matrix);
                }

0

Якщо ви хочете встановити масштаб зображення перед показом, використовуйте цей клас: https://github.com/MikeOrtiz/TouchImageView/blob/master/src/com/ortiz/touch/TouchImageView.java .

Також зображення можна змінити за допомогою подвійного натискання.

Якщо ви використовуєте ImageViewвнутрішнє a ViewPager, застосуйте це виправлення: https://github.com/MikeOrtiz/TouchImageView/isissue/125 .


0

Я думаю , чому ви хочете , щоб збільшити в і зменшити масштаб зображення виду тому , що ваш вид зображення малий і масштабування зображення не дозволить зображенню вийти з представлення зображення. Натомість зображення починає зникати з меж при збільшенні масштабу. Отже, випускати зображення із зображення під час збільшення масштабу - це те, що ви хочете, я думаю.

Тож є два хитрощі (на мою думку) для досягнення цього -

  1. Змініть параметри компонування зображення подання, щоб охопити весь зовнішній вигляд або групу перегляду під час виконання, поки ми збираємося збільшувати зображення.
  2. Зробіть розгорнутий перегляд зображення або повний перегляд зображення (висота та ширина = Зовнішній вигляд або Переглянути групу) у XML-файлі та встановіть, що його видимість зникла. Коли ми збираємось збільшити масштаб зображення, завантажте зображення з невеликого перегляду зображення в повний Img View, перетворіть зображення в fullImgView на зображення в smallImgView і зробіть його видимим.

Трюк №1 не працює, коли перегляд зображення вкладається дуже сильно в інші види (як у вкладеному перегляді рециркулятора)

Хитрість ні. 2 працює завжди :-)

Ось реалізація хитрості №2 -

public class ZoomOnTouchListener extends AppCompatActivity implements View.OnTouchListener {

    private Matrix matrix = new Matrix();

    private boolean isfullImgViewActive = false;
    // above boolean gets true when when we firstly move 2 fingers on the smallImgView and in this case smallImgView gets invisible and fullImgView gets visible
    // and false if smallImgView is visible and fullImgView is gone

    private float[] matrixArray = new float[9];
    private float orgScale;

    private PointF start = new PointF();
    private PointF prevP1 = new PointF();
    private PointF prevP2 = new PointF();
    private PointF mid = new PointF();
    private float oldDist = 1f;

    private ImageView mfullImgView;
    private ImageView smallImgView;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mfullImgView = (ImageView)findViewById(R.id.imgView2);
        mfullImgView.setVisibility(View.GONE);
        smallImgView = (ImageView)findViewById(R.id.imgView);
        smallImgView.setOnTouchListener(this);    

    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        //Log.i("0", "OnTouch()");
        if(v instanceof ImageView) {
            ImageView imgView = (ImageView) v;

            boolean isImgViewSmall = (imgView == smallImgView);

            switch (event.getAction() & MotionEvent.ACTION_MASK) {

                case MotionEvent.ACTION_DOWN:   // first finger down only

                    //Log.i("T", "Motion Event: ACTION_DOWN");

                    if(isImgViewSmall)
                        start.set(event.getX(), event.getY());

                    prevP1.set(event.getX(), event.getY());

                    return true;

                case MotionEvent.ACTION_POINTER_DOWN: //second finger and other fingers down

                    prevP1.set(event.getX(0), event.getY(0));
                    prevP2.set(event.getX(1), event.getY(1));

                    oldDist = spacing(event);

                    midPoint(mid, event);

                    break;

                case MotionEvent.ACTION_MOVE:   //it doesn't mean fingers are moved. In this case, all pointers which are active are batched together
                                                // this case occurs after action_down or action_pointer_down

                    //Log.i("Tag", event.getX()+","+event.getY());
                    if(event.getPointerCount() == 2) {

                        PointF newMid = new PointF();
                        midPoint(newMid,event);

                        float newDist = spacing(event);

                        float scale = newDist/oldDist;

                        if( !isfullImgViewActive){   // is smallImgView is visible and mfullImgView is gone
                            Log.i("tag", "true");

                            isfullImgViewActive = true;

                            matrix.set(imgView.getImageMatrix());   //note:- do not write matrix = imgView.getImageMatrix() because it gives the smallImgView's matrix reference to the matrix variable and changes on matrix will reflect on smallImgView
                            matrix.getValues(matrixArray);

                            orgScale = matrixArray[0];

                            smallImgView.setVisibility(View.INVISIBLE);

                            mfullImgView.setImageDrawable(smallImgView.getDrawable());
                            mfullImgView.setScaleType(ImageView.ScaleType.MATRIX);

                            mfullImgView.setVisibility(View.VISIBLE);

                            //To map the image of mFullImgView to that of smallImgView we have to 
                            // translate the mFullImgView's image
                            matrix.postTranslate(tx, ty);
                            /////////////NOTE///////////////
                            //here (tx,ty) are coordinates of top-left corner of smallimgView and 
                            // they MUST be relative to the origin of Outermost view or view group 
                            // where fullImgView is placed. So find tx,ty in your case by yourself

                            mfullImgView.setImageMatrix(matrix);      
                        }

                        if(isImgViewSmall) {
                            matrix.postScale(scale, scale, mid.x + tx, mid.y + ty);
                        }
                        else{
                            matrix.postScale(scale, scale, mid.x, mid.y);
                        }
                        oldDist = newDist;

                        matrix.postTranslate(newMid.x - mid.x, newMid.y - mid.y);

                        matrix.getValues(matrixArray);

                        mid.set(newMid);


                        prevP1.set(event.getX(0), event.getY(0));
                        prevP2.set(event.getX(1), event.getY(1));

                    }

                    else if(event.getPointerCount() == 1 ){

                        if(isfullImgViewActive) {

                            matrix.postTranslate(event.getX() - prevP1.x, event.getY() - prevP1.y);
                            matrix.getValues(matrixArray);
                        }

                        prevP1.set(event.getX(0), event.getY(0));

                    }

                    break;

                case MotionEvent.ACTION_POINTER_UP: // second finger lifted

                    //Now if pointer of index 0 is lifted then pointer of index 1 will get index 0;
                    if(event.getActionIndex() == 0 && isfullImgViewActive){
                        Log.i("TAg", event.getActionIndex()+"");
                        prevP1.set(prevP2);
                    }

                    break;

                case MotionEvent.ACTION_UP: // first finger lifted or all fingers are lifted

                    if(isImgViewSmall && !isfullImgViewActive) {

                        imgView.setScaleType(ImageView.ScaleType.FIT_CENTER);

                        int xDiff = (int) Math.abs(event.getX() - start.x);
                        int yDiff = (int) Math.abs(event.getY() - start.y);
                        if (xDiff == 0 && yDiff == 0) {
                            imgView.performClick();
                            return true;
                        }
                    }

                    if(isfullImgViewActive){
                        if(matrixArray[0] <= orgScale){  //matrixArray[0] is Scale.X value

                            mfullImgView.setOnTouchListener(null);
                            mfullImgView.setImageDrawable(null);
                            mfullImgView.setVisibility(View.GONE);

                            smallImgView.setOnTouchListener(this);
                            smallImgView.setScaleType(ImageView.ScaleType.FIT_CENTER);
                            smallImgView.setVisibility(View.VISIBLE);

                            isfullImgViewActive = false;

                        }
                        else if(matrixArray[0] > orgScale && isImgViewSmall){  //if the imgView was smallImgView

                            smallImgView.setOnTouchListener(null);
                            smallImgView.setScaleType(ImageView.ScaleType.FIT_CENTER);
                            smallImgView.setVisibility(View.GONE);  // or View.INVISIBLE

                            mfullImgView.setOnTouchListener(this);
                        }
                    }

                    return true;


            }
            //end of Switch statement


            if(isfullImgViewActive) {   //active means visible
                mfullImgView.setImageMatrix(matrix); // display the transformation on screen
            }

            return true; // indicate event was handled
        }
        else
            return false;
    }


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


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

}

ПРИМІТКА: - Не встановлюйте OnClickListener на mfullImgView, перш ніж встановлювати на нього OnTouchListener. Налаштування, яке дозволить fullImageView (якщо воно видно), вкраде дотик дотику відведення другого пальця після його першого піднімання, тому що ми хочемо дозволити smallImgView прийняти всі події дотику до тих пір, поки всі пальці не будуть підняті вгору для першого час.


-2

Я використовую цей, він працює чудово.

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

Мій клас MyZoomableImageViewTouch наведено нижче:

public class MyZoomableImageViewTouch extends ImageViewTouch
{

    static final float SCROLL_DELTA_THRESHOLD = 1.0f;

    public MyZoomableImageViewTouch(Context context, AttributeSet attrs, int defStyle)
    {
        super(context, attrs, defStyle);
        init();
    }

    public MyZoomableImageViewTouch(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public MyZoomableImageViewTouch(Context context)
    {
        super(context);
        init();
    }

    private void init() {
        View.OnTouchListener listener = new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (getScale() > 1f) {
                    getParent().requestDisallowInterceptTouchEvent(true);
                } else {
                    getParent().requestDisallowInterceptTouchEvent(false);
                }
                return false;
            }
        };
        setOnTouchListener(listener);
        setDisplayType(DisplayType.FIT_TO_SCREEN);
    }

    @Override
    protected float onDoubleTapPost(float scale, float maxZoom) {
        if (scale != 1f) {
            mDoubleTapDirection = 1;
            return 1f;
        }
        if (mDoubleTapDirection == 1) {
            mDoubleTapDirection = -1;
            if ((scale + (mScaleFactor * 2)) <= maxZoom) {
                return scale + mScaleFactor;
            } else {
                mDoubleTapDirection = -1;
                return maxZoom;
            }
        } else {
            mDoubleTapDirection = 1;
            return 1f;
        }
    }

    @Override
    public boolean canScroll(int direction) {
        RectF bitmapRect = getBitmapRect();
        updateRect(bitmapRect, mScrollRect);
        Rect imageViewRect = new Rect();
        getGlobalVisibleRect(imageViewRect);

        if (null == bitmapRect) {
            return false;
        }

        if (Math.abs(bitmapRect.right - imageViewRect.right) < SCROLL_DELTA_THRESHOLD) {
            if (direction < 0) {
                return false;
            }
        }

        if (Math.abs(bitmapRect.left - mScrollRect.left) < SCROLL_DELTA_THRESHOLD) {
            if (direction > 0) {
                return false;
            }
        }
        return true;
    }

    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY)
    {
        if (getScale() == 1f) return false;
        if (distanceX != 0 && !canScroll((int) -distanceX)) {
            getParent().requestDisallowInterceptTouchEvent(false);
            return false;
        } else {
            getParent().requestDisallowInterceptTouchEvent(true);
            mUserScaled = true;
            scrollBy(-distanceX, -distanceY);
            invalidate();
            return true;
        }
    }
}

у вашому прикладі є неповний код, стільки помилок та класу ImageViewTouch відсутні.
Däñish Shärmà
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.