¿Cómo puedo obtener la funcionalidad de zoom para imágenes?

204

¿Existe una forma común de mostrar una imagen grande y permitir al usuario acercar y alejar y desplazar la imagen?

Hasta ahora encontré dos formas:

  1. sobrescribir ImageView, eso parece demasiado para un problema tan común.
  2. usando una vista web pero con menos control sobre el diseño general, etc.
Janusz
fuente
Hay un CONTROL DE ZOOM (Widget) y puede escuchar el evento OnTouch para manejar la panorámica.
tobrien
1
Una pregunta similar stackoverflow.com/questions/2537396/… , tiene un enlace a este tutorial anddev.org/… . Puede que le resulte útil para desplazar su imagen. No lo he leído en detalle, pero también podría darle algunas ideas sobre cómo hacer la función de zoom.
Steve Haley
¿Alguien ha intentado guardar la imagen al hacer zoom? Quiero que la imagen guardada tenga un estado predeterminado en lugar del estado ampliado. Por favor vea mi pregunta: stackoverflow.com/questions/24730793/… Gracias
Blaze Tama

Respuestas:

208

ACTUALIZAR

Acabo de darle a TouchImageView una nueva actualización. Ahora incluye Double Tap Zoom y Fling además de Panning y Pinch Zoom. El siguiente código está muy anticuado. Puede consultar el proyecto github para obtener el último código.

USO

Coloque TouchImageView.java en su proyecto. Luego se puede usar igual que ImageView. Ejemplo:

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

Si está utilizando TouchImageView en xml, debe proporcionar el nombre completo del paquete, ya que es una vista personalizada. Ejemplo:

<com.example.touch.TouchImageView
    android:id="@+id/img”
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

Nota: Eliminé mi respuesta anterior, que incluía un código muy antiguo y ahora enlazo directamente al código más actualizado en github.

ViewPager

Si está interesado en colocar TouchImageView en un ViewPager, consulte esta respuesta.

Mike Ortiz
fuente
44
Paulo, no me encontré con problemas de rendimiento, pero no pude probar en una tableta. Por lento, ¿quieres decir lento? Establecí un factor de zoom máximo de 1.05 al comienzo de onScale. ¿Es esto de lo que estás hablando? Si no, intente lo siguiente: 1. ¿Está en modo de depuración? Esto lo ralentizaría significativamente. 2. ¿Qué tamaño de imágenes está configurando? No probé con imágenes muy grandes (8mp), pero esto podría ralentizarlo. 3. ¿Tiene un teléfono que pueda probar? 4. Si todo lo demás falla, vea si multiplicar mScaleFactor por 2 (si> 1) o 0.5 (si <1) ayuda a su situación.
Mike Ortiz
3
@Ahsan Cambie el constructor de la vista a: TouchImageView(Context context, AttributeSet attrs)y llame super(context, attrs);Esto se debe a que cuando infla la vista personalizada, se construye con dos parámetros, en lugar de solo uno. Cuando llegue a eso, arreglaré TouchImageView para que sea compatible con los tres constructores de vista y elementos dibujables.
Mike Ortiz
2
@Ahsan Debido a que es una vista personalizada, debe escribir el nombre completo en el archivo XML, es decir <com.example.TouchImageView android:id="@+id/img" />. ¿Hiciste eso?
Mike Ortiz el
1
Esto es genial, lo he estado buscando por años. Utilice el código de github ya que es más reciente y funciona mejor
Alex
2
@ Mike, he probado este código pero la galería personalizada no funciona. ¿Hay algún truco para solucionar este problema?
Umesh
80

Adapte un código para crear un TouchImageView que sea compatible con multitouch (> 2.1). Está inspirado en el libro Hello, Android! (3a edición)

Está contenido en los siguientes 3 archivos TouchImageView.java WrapMotionEvent.java EclairMotionEvent.java

TouchImageView.java

import se.robertfoss.ChanImageBrowser.Viewer;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.util.FloatMath;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;

public class TouchImageView extends ImageView {

    private static final String TAG = "Touch";
    // These matrices will be used to move and zoom image
    Matrix matrix = new Matrix();
    Matrix savedMatrix = new 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 start = new PointF();
    PointF mid = new PointF();
    float oldDist = 1f;

    Context context;


    public TouchImageView(Context context) {
        super(context);
        super.setClickable(true);
        this.context = context;

        matrix.setTranslate(1f, 1f);
        setImageMatrix(matrix);
        setScaleType(ScaleType.MATRIX);

        setOnTouchListener(new OnTouchListener() {

            @Override
            public boolean onTouch(View v, MotionEvent rawEvent) {
                WrapMotionEvent event = WrapMotionEvent.wrap(rawEvent);

                // Dump touch event to log
                if (Viewer.isDebug == true){
                    dumpEvent(event);
                }

                // Handle touch events here...
                switch (event.getAction() & MotionEvent.ACTION_MASK) {
                case MotionEvent.ACTION_DOWN:
                    savedMatrix.set(matrix);
                    start.set(event.getX(), event.getY());
                    Log.d(TAG, "mode=DRAG");
                    mode = DRAG;
                    break;
                case MotionEvent.ACTION_POINTER_DOWN:
                    oldDist = spacing(event);
                    Log.d(TAG, "oldDist=" + oldDist);
                    if (oldDist > 10f) {
                        savedMatrix.set(matrix);
                        midPoint(mid, event);
                        mode = ZOOM;
                        Log.d(TAG, "mode=ZOOM");
                    }
                    break;
                case MotionEvent.ACTION_UP:
                    int xDiff = (int) Math.abs(event.getX() - start.x);
                    int yDiff = (int) Math.abs(event.getY() - start.y);
                    if (xDiff < 8 && yDiff < 8){
                        performClick();
                    }
                case MotionEvent.ACTION_POINTER_UP:
                    mode = NONE;
                    Log.d(TAG, "mode=NONE");
                    break;
                case MotionEvent.ACTION_MOVE:
                    if (mode == DRAG) {
                        // ...
                        matrix.set(savedMatrix);
                        matrix.postTranslate(event.getX() - start.x, event.getY() - start.y);
                    } else if (mode == ZOOM) {
                        float newDist = spacing(event);
                        Log.d(TAG, "newDist=" + newDist);
                        if (newDist > 10f) {
                            matrix.set(savedMatrix);
                            float scale = newDist / oldDist;
                            matrix.postScale(scale, scale, mid.x, mid.y);
                        }
                    }
                    break;
                }

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

        });
    }


    public void setImage(Bitmap bm, int displayWidth, int displayHeight) { 
        super.setImageBitmap(bm);

        //Fit to screen.
        float scale;
        if ((displayHeight / bm.getHeight()) >= (displayWidth / bm.getWidth())){
            scale =  (float)displayWidth / (float)bm.getWidth();
        } else {
            scale = (float)displayHeight / (float)bm.getHeight();
        }

        savedMatrix.set(matrix);
        matrix.set(savedMatrix);
        matrix.postScale(scale, scale, mid.x, mid.y);
        setImageMatrix(matrix);


        // Center the image
        float redundantYSpace = (float)displayHeight - (scale * (float)bm.getHeight()) ;
        float redundantXSpace = (float)displayWidth - (scale * (float)bm.getWidth());

        redundantYSpace /= (float)2;
        redundantXSpace /= (float)2;


        savedMatrix.set(matrix);
        matrix.set(savedMatrix);
        matrix.postTranslate(redundantXSpace, redundantYSpace);
        setImageMatrix(matrix);
    }


    /** Show an event in the LogCat view, for debugging */
    private void dumpEvent(WrapMotionEvent 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(WrapMotionEvent 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 */
    private void midPoint(PointF point, WrapMotionEvent event) {
        // ...
        float x = event.getX(0) + event.getX(1);
        float y = event.getY(0) + event.getY(1);
        point.set(x / 2, y / 2);
    }
}

WrapMotionEvent.java

import android.view.MotionEvent;

public class WrapMotionEvent {
protected MotionEvent event;




    protected WrapMotionEvent(MotionEvent event) {
        this.event = event;
    }

    static public WrapMotionEvent wrap(MotionEvent event) {
            try {
                return new EclairMotionEvent(event);
            } catch (VerifyError e) {
                return new WrapMotionEvent(event);
            }
    }



    public int getAction() {
            return event.getAction();
    }

    public float getX() {
            return event.getX();
    }

    public float getX(int pointerIndex) {
            verifyPointerIndex(pointerIndex);
            return getX();
    }

    public float getY() {
            return event.getY();
    }

    public float getY(int pointerIndex) {
            verifyPointerIndex(pointerIndex);
            return getY();
    }

    public int getPointerCount() {
            return 1;
    }

    public int getPointerId(int pointerIndex) {
            verifyPointerIndex(pointerIndex);
            return 0;
    }

    private void verifyPointerIndex(int pointerIndex) {
            if (pointerIndex > 0) {
                throw new IllegalArgumentException(
                    "Invalid pointer index for Donut/Cupcake");
            }
    }

}

EclairMotionEvent.java

import android.view.MotionEvent;

public class EclairMotionEvent extends WrapMotionEvent {

    protected EclairMotionEvent(MotionEvent event) {
            super(event);
    }

    public float getX(int pointerIndex) {
            return event.getX(pointerIndex);
    }

    public float getY(int pointerIndex) {
            return event.getY(pointerIndex);
    }

    public int getPointerCount() {
            return event.getPointerCount();
    }

    public int getPointerId(int pointerIndex) {
            return event.getPointerId(pointerIndex);
    }
}
Robert Foss
fuente
Robert Foss, si esto agrega un juez de límite, puede caer más bien. Gracias su código muy bien
pengwang
3
Funciona, pero no veo el punto WrapMotionEventy EclairMotionEvent... de todos modos, +1.
Cipi
2
Multitáctil para teléfonos que lo admiten. Un toque habitual para Android <2.0
Robert Foss
Un buen ejemplo funciona bien, pero no obtuve lo que es Viewer en if (Viewer.isDebug == true) {dumpEvent (event); }
Tofeeq Ahmad
2
¿Que es esto? >> se.robertfoss.ChanImageBrowser.Viewer
emeraldhieu
60

Utilicé un WebView y cargué la imagen desde la memoria a través de

webview.loadUrl("file://...")

WebView maneja todos los desplazamientos, zoom, desplazamiento. Si usa wrap_content, la vista web no será más grande que la imagen y no se muestran áreas blancas. El WebView es el mejor ImageView;)

Janusz
fuente
55
Estoy usando el mismo enfoque. Tengo un gran mapa del metro que quiero que el usuario pueda hacer zoom y desplazarse. Sin embargo, me di cuenta de que si tiene una imagen bastante grande (es decir, 1000 o 3000 píxeles de ancho), la imagen se vuelve borrosa una vez que se acerca. Parece que coliris no puede mostrar una imagen ampliada muy nítida. Aunque la imagen original no está comprimida y es muy nítida. Por lo tanto, terminé cortando la imagen grande en porciones más pequeñas y volviéndolas a juntar a través de HTML. De esta manera, la imagen se mantiene nítida cuando se acerca. (Estoy en Nexus One, 2.1update antes y ahora en 2.2)
Mathias Conradt
@Mathias Lin: si se envía una imagen grande por cable, escuché que los operadores comprimen imágenes grandes. ¿este caso de uso le conviene o cargó la imagen localmente?
Samuel
@Sam Quest: cargando localmente
Mathias Conradt
44
es mucho mejor usar los botones de zoom integrados de webview y la compatibilidad para pellizcar para acercar / alejar que escribir un algo completamente nuevo que puede no funcionar en diferentes teléfonos y futuras versiones de la plataforma Android
sami
2
esta solución solo se puede aplicar si tiene la imagen en el disco, o si la imagen es lo suficientemente pequeña como para que pueda codificar en base 64 y pasar el valor de la cadena a loadUrlWithData ().
Jeffrey Blattman
7

En respuesta a la pregunta original de Janusz, hay varias formas de lograr esto, todas las cuales varían en su nivel de dificultad y se han indicado a continuación. Usar una vista web es bueno, pero es muy limitado en términos de apariencia y control. Si está dibujando un mapa de bits desde un lienzo, las soluciones más versátiles que se han propuesto parecen ser las de MikeOrtiz, Robert Foss y / o lo que sugirió Jacob Nordfalk. Hay un gran ejemplo para la incorporación de la android-multitouch-controlador por PaulBourke , y es ideal para contar con el apoyo multitouch y AllTypes de vistas personalizadas.

Personalmente, si simplemente está dibujando un lienzo en un mapa de bits y luego lo muestra en el interior y en ImageView y desea poder acercarse y moverse con el toque múltiple, la solución de MikeOrtiz es la más fácil. Sin embargo, para mis propósitos, el código del Git que ha proporcionado parece funcionar solo cuando su clase TouchViewView personalizada ImageView es el único elemento secundario o proporciona los parámetros de diseño como:

android:layout_height="match_parent"
android:layout_height="match_parent"

Desafortunadamente debido a mi diseño de diseño, necesitaba "wrap_content" para "layout_height". Cuando lo cambié a esto, la imagen se recortó en la parte inferior y no pude desplazarme ni acercarme a la región recortada. Así que eché un vistazo a Source for ImageView solo para ver cómo Android implementó "onMeasure" y cambié MikeOrtiz para adaptarlo.

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

  //**** ADDED THIS ********/////
      int  w = (int) bmWidth;
      int  h = (int) bmHeight;
     width = resolveSize(w, widthMeasureSpec);  
     height = resolveSize(h, heightMeasureSpec);
  //**** END ********///   

   // width = MeasureSpec.getSize(widthMeasureSpec);   // REMOVED
   // height = MeasureSpec.getSize(heightMeasureSpec); // REMOVED

    //Fit to screen.
    float scale;
    float scaleX =  (float)width / (float)bmWidth;
    float scaleY = (float)height / (float)bmHeight;

    scale = Math.min(scaleX, scaleY);
    matrix.setScale(scale, scale);
    setImageMatrix(matrix);
    saveScale = 1f;

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

    matrix.postTranslate(redundantXSpace, redundantYSpace);

    origWidth = width - 2 * redundantXSpace;
    origHeight = height - 2 * redundantYSpace;
   // origHeight = bmHeight;
    right = width * saveScale - width - (2 * redundantXSpace * saveScale);
    bottom = height * saveScale - height - (2 * redundantYSpace * saveScale);

    setImageMatrix(matrix);
}

Aquí resolveSize (int, int) es una "Utilidad para conciliar un tamaño deseado con restricciones impuestas por un MeasureSpec, donde:

Parámetros:

 - size How big the view wants to be
 - MeasureSpec Constraints imposed by the parent

Devoluciones:

 - The size this view should be."

Por lo tanto, esencialmente proporciona un comportamiento un poco más similar a la clase ImageView original cuando se carga la imagen. Se podrían realizar algunos cambios más para admitir una mayor variedad de pantallas que modifiquen la relación de aspecto. Pero por ahora espero que esto ayude. Gracias a MikeOrtiz por su código original, gran trabajo.

digiphd
fuente
¿Se ha incorporado esta solución al repositorio github de Mike?
LarsH
6

Acabo de integrar TouchImageView de Robert Foss: ¡funcionó perfectamente fuera de la caja! ¡Gracias!

Acabo de modificar un poco el código para poder crear una instancia desde mi layout.xml.

Solo agrega dos constructores

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

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

y transforma el viejo constructor en un método init:

private void init(Context context){
    //...old code ofconstructor of Robert Moss's code
}
zontar
fuente
3

@Robert Foss, @Mike Ortiz, muchas gracias por tu trabajo. Fusioné tu trabajo y completé las clases de Robert para Android> 2.0 con el trabajo adicional de Mike.

Como resultado de mi trabajo, presento Android Touch Gallery, basado en ViewPager y utilicé TouchImageView modificado. Las imágenes se cargan por URL y puede hacer zoom y arrastrarlas. Puede encontrarlo aquí https://github.com/Dreddik/AndroidTouchGallery

Truba romana
fuente
2

Agregando a la respuesta de @ Mike. También necesité tocar dos veces para restaurar la imagen a las dimensiones originales cuando la vi por primera vez. Así que agregué un montón completo de variables de instancia "orig ..." y agregué SimpleOnGestureListener que hizo el truco.

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.PointF;
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 = new 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;;

    float width, height;
    static final int CLICK = 3;
    static final float SAVE_SCALE = 1f;
    float saveScale = SAVE_SCALE;

    float right, bottom, origWidth, origHeight, bmWidth, bmHeight, origScale, origBottom,origRight;

    ScaleGestureDetector mScaleDetector;
    GestureDetector mGestureDetector;

    Context context;

    public TouchImageView(Context context) {
        super(context);
        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) {

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

                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()) {
                case MotionEvent.ACTION_DOWN:
                    last.set(event.getX(), event.getY());
                    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 scaleWidth = Math.round(origWidth * saveScale);
                        float scaleHeight = Math.round(origHeight * saveScale);
                        if (scaleWidth < width) {
                            deltaX = 0;
                            if (y + deltaY > 0)
                                deltaY = -y;
                            else if (y + deltaY < -bottom)
                                deltaY = -(y + bottom);
                        } else if (scaleHeight < height) {
                            deltaY = 0;
                            if (x + deltaX > 0)
                                deltaX = -x;
                            else if (x + deltaX < -right)
                                deltaX = -(x + 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);
                        }
                        matrix.postTranslate(deltaX, deltaY);
                        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;
            }
        });
    }

    @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 = (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 = 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 = (float) width / (float) bmWidth;
        float scaleY = (float) height / (float) bmHeight;
        scale = Math.min(scaleX, scaleY);
        matrix.setScale(scale, scale);
        setImageMatrix(matrix);
        saveScale = SAVE_SCALE;
        origScale = scale;

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

        origRedundantXSpace = redundantXSpace;
        origRedundantYSpace = redundantYSpace;

        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);
        origRight = right;
        origBottom = bottom;
        setImageMatrix(matrix);
    }

}
Terence
fuente
2

Esta es una adición muy tardía a este hilo, pero he estado trabajando en una vista de imagen que admite zoom y panorámica y tiene un par de características que no he encontrado en ningún otro lado. Esto comenzó como una forma de mostrar imágenes muy grandes sin causar OutOfMemoryErrors, submuestreando la imagen cuando se aleja y cargando mosaicos de mayor resolución cuando se acerca. Ahora admite el uso en una ViewPagerrotación manual o el uso de información EXIF ​​(paradas de 90 °), anular de eventos de toque seleccionados usando OnClickListenero en su propio GestureDetectoro OnTouchListener, como subclase añadir superposiciones, cacerola mientras que el zoom, y lanzar impulso.

No pretende ser un reemplazo de uso general, por ImageViewlo que no lo extiende y no admite la visualización de imágenes de recursos, solo activos y archivos externos. Requiere SDK 10.

La fuente está en GitHub, y hay una muestra que ilustra el uso en a ViewPager.

https://github.com/davemorrissey/subsampling-scale-image-view

Dave Morrissey
fuente
1

Puede intentar usar los LayoutParams para esto

public void zoom(boolean flag){
    if(flag){
        int width=40;
        int height=40;
    }
    else{
        int width=20;
        int height=20;
    }
    RelativeLayout.LayoutParams param=new RelativeLayout.LayoutParams(width,height); //use the parent layout of the ImageView;
    imageView.setLayoutParams(param); //imageView is the view which needs zooming.
}

ZoomIn = zoom (verdadero); ZoomOut = zoom (falso);

novato
fuente
0
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    imageDetail = (ImageView) findViewById(R.id.imageView1);
    imageDetail.setOnTouchListener(new View.OnTouchListener() {

        @Override
        public boolean onTouch(View v, MotionEvent event) {
            ImageView view = (ImageView) v;
            System.out.println("matrix=" + savedMatrix.toString());
            switch (event.getAction() & MotionEvent.ACTION_MASK) {
                case MotionEvent.ACTION_DOWN:
                    savedMatrix.set(matrix);
                    startPoint.set(event.getX(), event.getY());
                    mode = DRAG;
                    break;
                case MotionEvent.ACTION_POINTER_DOWN:
                    oldDist = spacing(event);
                    if (oldDist > 10f) {
                        savedMatrix.set(matrix);
                        midPoint(midPoint, event);
                        mode = ZOOM;
                    }
                    break;
                case MotionEvent.ACTION_UP:
                case MotionEvent.ACTION_POINTER_UP:
                    mode = NONE;
                    break;
                case MotionEvent.ACTION_MOVE:
                    if (mode == DRAG) {
                        matrix.set(savedMatrix);
                        matrix.postTranslate(event.getX() - startPoint.x, event.getY() - startPoint.y);
                    } else if (mode == ZOOM) {
                        float newDist = spacing(event);
                        if (newDist > 10f) {
                            matrix.set(savedMatrix);
                            float scale = newDist / oldDist;
                            matrix.postScale(scale, scale, midPoint.x, midPoint.y);
                        }
                    }
                    break;
            }
            view.setImageMatrix(matrix);
            return true;

        }

        @SuppressLint("FloatMath")
        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);
        }

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

y la carpeta dibujable debe tener un archivo de imagen bticn. funciona perfectamente :)

Muhammad Usman Ghani
fuente
0

Algo como a continuación lo hará.

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

    tap=tap2=drag=pinch=none;
    int mask=e.getActionMasked();
    posx=e.getX();posy=e.getY();

    float midx= img.getWidth()/2f;
    float midy=img.getHeight()/2f;
    int fingers=e.getPointerCount();

    switch(mask)
    {
        case MotionEvent.ACTION_POINTER_UP:
            tap2=1;break;

        case MotionEvent.ACTION_UP:
            tap=1;break;

        case MotionEvent.ACTION_MOVE:
            drag=1;
    }
    if(fingers==2){nowsp=Math.abs(e.getX(0)-e.getX(1));}
    if((fingers==2)&&(drag==0)){ tap2=1;tap=0;drag=0;}
    if((fingers==2)&&(drag==1)){ tap2=0;tap=0;drag=0;pinch=1;}

    if(pinch==1)

    {
        if(nowsp>oldsp)scale+=0.1;
        if(nowsp<oldsp)scale-=0.1;
        tap2=tap=drag=0;    
    }
    if(tap2==1)
        {
            scale-=0.1;
            tap=0;drag=0;
        }
    if(tap==1)
        {
            tap2=0;drag=0;
            scale+=0.1;
        }
    if(drag==1)
        {
            movx=posx-oldx;
            movy=posy-oldy;
            x+=movx;
            y+=movy;
            tap=0;tap2=0;
        }
    m.setTranslate(x,y);
    m.postScale(scale,scale,midx,midy);
    img.setImageMatrix(m);img.invalidate();
    tap=tap2=drag=none;
    oldx=posx;oldy=posy;
    oldsp=nowsp;
    return true;
}


public void onCreate(Bundle b)
{
        super.onCreate(b);

    img=new ImageView(this);
    img.setScaleType(ImageView.ScaleType.MATRIX);
    img.setOnTouchListener(this);

    path=Environment.getExternalStorageDirectory().getPath();   
    path=path+"/DCIM"+"/behala.jpg";
    byte[] bytes;
    bytes=null;
    try{
        FileInputStream fis;
        fis=new FileInputStream(path);
        BufferedInputStream bis;
        bis=new BufferedInputStream(fis);
        bytes=new byte[bis.available()];
        bis.read(bytes);
        if(bis!=null)bis.close();
        if(fis!=null)fis.close();

     }
    catch(Exception e)
        {
        ret="Nothing";
        }
    Bitmap bmp=BitmapFactory.decodeByteArray(bytes,0,bytes.length);

    img.setImageBitmap(bmp);

    setContentView(img);
}

Para ver el programa completo, vea aquí: Programa para ampliar la imagen en Android

Animesh Shrivastav
fuente