Comment obtenir la fonctionnalité de zoom pour les images?

204

Existe-t-il un moyen courant d'afficher une grande image et de permettre à l'utilisateur de faire un zoom avant et arrière et de faire un panoramique sur l'image?

Jusqu'à présent, j'ai trouvé deux façons:

  1. écraser ImageView, cela semble un peu trop pour un problème aussi courant.
  2. en utilisant une vue Web mais avec moins de contrôle sur la mise en page globale, etc.
Janusz
la source
Il y a un ZOOM CONTROL (Widget) et vous pouvez écouter l'événement OnTouch pour gérer le panoramique.
tobrien
1
Une question similaire stackoverflow.com/questions/2537396/… , a un lien vers ce tutoriel etdev.org/… . Vous pourriez trouver cela utile pour effectuer un panoramique sur votre iamge. Je ne l'ai pas lu en détail, mais cela pourrait également vous donner quelques idées sur la façon de faire la fonction zoom.
Steve Haley
Quelqu'un at-il essayé d'enregistrer l'image lors du zoom? Je veux que l'image enregistrée soit dans un état par défaut au lieu de l'état agrandi. Veuillez voir ma question: stackoverflow.com/questions/24730793/… Merci
Blaze Tama

Réponses:

208

METTRE À JOUR

Je viens de donner à TouchImageView une nouvelle mise à jour. Il comprend désormais le zoom double pression et le lancer en plus du zoom panoramique et pincé. Le code ci-dessous est très daté. Vous pouvez consulter le projet github pour obtenir le dernier code.

USAGE

Placez TouchImageView.java dans votre projet. Il peut ensuite être utilisé de la même manière que ImageView. Exemple:

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

Si vous utilisez TouchImageView en xml, vous devez fournir le nom complet du package, car il s'agit d'une vue personnalisée. Exemple:

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

Remarque: J'ai supprimé ma réponse précédente, qui comprenait un code très ancien et qui relie maintenant directement le code le plus récent sur github.

ViewPager

Si vous souhaitez mettre TouchImageView dans un ViewPager, reportez - vous à cette réponse.

Mike Ortiz
la source
4
Paulo, je n'ai pas rencontré de problèmes de performances, mais je n'ai pas pu tester sur une tablette. Par lent, tu veux dire laggy? J'ai défini un facteur de zoom maximal de 1,05 au début de onScale. Est-ce de cela dont vous parlez? Sinon, essayez ce qui suit: 1. Êtes-vous en mode débogage? Cela le ralentirait considérablement. 2. Quelle taille d'images définissez-vous? Je n'ai pas testé avec des images très grandes (8mp), mais cela pourrait ralentir. 3. Avez-vous un téléphone sur lequel vous pourriez tester? 4. Si tout le reste échoue, voyez si la multiplication de mScaleFactor par 2 (si> 1) ou 0,5 (si <1) aide votre situation.
Mike Ortiz
3
@Ahsan Remplacez le constructeur View par: TouchImageView(Context context, AttributeSet attrs)et appelez super(context, attrs);-le parce que lorsque vous gonflez la vue personnalisée, elle est construite avec deux paramètres, plutôt qu'un seul. Lorsque j'y arriverai, je corrigerai TouchImageView pour prendre en charge les trois constructeurs de vues et les dessinables.
Mike Ortiz
2
@Ahsan Comme il s'agit d'une vue personnalisée, vous devez écrire le nom complet dans le fichier XML, c'est-à-dire <com.example.TouchImageView android:id="@+id/img" />. As-tu fais ça?
Mike Ortiz
1
C'est un truc génial, je le cherche depuis des lustres. Utilisez le code de github car il est plus récent et fonctionne mieux
Alex
2
@ Mike, j'ai essayé ce code mais la galerie personnalisée ne fonctionne pas. Existe-t-il une astuce pour contourner ce problème?
Umesh
80

J'ai adapté du code pour créer un TouchImageView qui prend en charge le multitouch (> 2.1). Il s'inspire du livre Hello, Android! (3e édition)

Il est contenu dans les 3 fichiers suivants 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
la source
Robert Foss, si ce juge de limite ajoute, il peut tomber plus
bien.Merci
3
Cela fonctionne, mais je ne vois pas l'intérêt WrapMotionEventet EclairMotionEvent... de toute façon, +1.
Cipi
2
Multitouch pour les téléphones qui le prennent en charge. Une touche régulière pour Android <2.0
Robert Foss
Bel exemple, cela fonctionne bien, mais je n'ai pas obtenu la visionneuse dans if (Viewer.isDebug == true) {dumpEvent (event); }
Tofeeq Ahmad
2
Qu'est-ce que c'est? >> se.robertfoss.ChanImageBrowser.Viewer
emeraldhieu
60

J'ai utilisé une WebView et chargé l'image de la mémoire via

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

Le WebView gère tout le zoom et le défilement panoramique. Si vous utilisez wrap_content, la vue Web ne sera pas plus grande que l'image et aucune zone blanche n'est affichée. Le WebView est le meilleur ImageView;)

Janusz
la source
5
J'utilise la même approche. J'ai une grande carte de métro que je veux que l'utilisateur puisse zoomer et faire défiler. J'ai remarqué cependant que si vous avez une image assez grande (c'est-à-dire 1000 ou 3000 pixels de large), l'image devient floue une fois que vous zoomez. Il semble que coliris ne puisse pas afficher une grande image zoomée très nette. Même si l'image d'origine n'est pas compressée et très nette. Par conséquent, j'ai fini par couper la grande image en tranches plus petites et les recomposer via HTML. De cette façon, l'image reste nette lors d'un zoom avant. (Je suis sur Nexus One, 2.1update avant et maintenant sur 2.2)
Mathias Conradt
@Mathias Lin: si une grande image est envoyée sur le fil, j'ai entendu des transporteurs compresser de grandes images. ce cas d'utilisation vous conviendra-t-il ou avez-vous chargé l'image localement.
Samuel
@Sam Quest: chargement local
Mathias Conradt
4
beaucoup mieux d'utiliser les boutons de zoom intégrés de Webview et la prise en charge de pincer pour zoomer / dézoomer que d'écrire un algo complètement nouveau qui pourrait ne pas fonctionner sur différents téléphones et versions futures de la plateforme Android
sami
2
cette solution ne peut être appliquée que si l'image se trouve sur le disque ou si l'image est suffisamment petite pour que vous puissiez baser l'encodage 64 et transmettre la valeur de chaîne à loadUrlWithData ().
Jeffrey Blattman
7

En réponse à la question originale de Janusz, il existe plusieurs façons d'y parvenir, qui varient toutes selon leur niveau de difficulté et ont été décrites ci-dessous. L'utilisation d'une vue Web est bonne, mais elle est très limitée en termes de look and feel et de contrôlabilité. Si vous dessinez une image bitmap à partir d'un canevas, les solutions les plus polyvalentes qui ont été proposées semblent être celles de MikeOrtiz, Robert Foss et / ou ce que Jacob Nordfalk a suggéré. Il existe un excellent exemple pour incorporer le contrôleur android-multitouch de PaulBourke , et est idéal pour avoir le support multi-touch et tous les types de vues personnalisées.

Personnellement, si vous dessinez simplement un canevas sur une image bitmap puis que vous l'affichez à l'intérieur et ImageView et que vous souhaitez pouvoir zoomer et vous déplacer en utilisant le multi-touch, je trouve la solution de MikeOrtiz la plus simple. Cependant, pour mes besoins, le code du Git qu'il a fourni semble fonctionner uniquement lorsque sa classe ImageView personnalisée TouchImageView est le seul enfant ou fournit les paramètres de mise en page comme:

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

Malheureusement, en raison de ma conception de mise en page, j'avais besoin de "wrap_content" pour "layout_height". Lorsque je l'ai changé, l'image a été recadrée en bas et je n'ai pas pu faire défiler ou zoomer sur la zone recadrée. J'ai donc jeté un œil à la Source pour ImageView juste pour voir comment Android a implémenté "onMeasure" et a changé MikeOrtiz pour l'adapter.

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

Ici resolSize (int, int) est un "utilitaire pour réconcilier une taille souhaitée avec des contraintes imposées par un MeasureSpec, où:

Paramètres:

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

Retour:

 - The size this view should be."

Offrant donc essentiellement un comportement un peu plus similaire à la classe ImageView d'origine lorsque l'image est chargée. D'autres modifications pourraient être apportées pour prendre en charge une plus grande variété d'écrans qui modifient le rapport d'aspect. Mais pour l'instant, j'espère que cela vous aidera. Merci à MikeOrtiz pour son code original, excellent travail.

digiphd
la source
Ce correctif a-t-il été intégré au dépôt github de Mike?
LarsH
6

Je viens d'intégrer TouchImageView de Robert Foss: cela a parfaitement fonctionné dès la sortie de la boîte! Merci!

Je viens de modifier un peu le code pour pouvoir l'instancier à partir de mon layout.xml.

Ajoutez simplement deux constructeurs

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

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

et transformer l'ancien constructeur en une méthode init:

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

@Robert Foss, @Mike Ortiz, merci beaucoup pour votre travail. J'ai fusionné votre travail et terminé les cours Robert pour Android> 2.0 avec du travail supplémentaire pour Mike.

À la suite de mon travail, je présente Android Touch Gallery, basé sur ViewPager et utilisé TouchImageView modifié. Les images se chargent par URL et vous pouvez les zoomer et les faire glisser. Vous pouvez le trouver ici https://github.com/Dreddik/AndroidTouchGallery

Roman Truba
la source
2

Essayez d'utiliser ZoomViewpour zoomer toute autre vue.

http://code.google.com/p/android-zoom-view/ c'est facile, gratuit et amusant à utiliser!

karooolek
la source
Ce référentiel n'est plus maintenu.
erginduran
2

Ajout à la réponse de @ Mike. J'ai également eu besoin d'appuyer deux fois pour restaurer l'image aux dimensions d'origine lors de sa première visualisation. J'ai donc ajouté un tas de variables d'instance "orig ..." et ajouté SimpleOnGestureListener qui a fait l'affaire.

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
la source
2

Ceci est un ajout très tardif à ce fil, mais j'ai travaillé sur une vue d'image qui prend en charge le zoom et le panoramique et possède quelques fonctionnalités que je n'ai pas trouvées ailleurs. Cela a commencé comme un moyen d'afficher de très grandes images sans causer OutOfMemoryErrors, par sous - échantillonnage de l'image lors de zoom arrière et tuiles chargement de plus haute résolution lors d'un zoom. Désormais , il permet d' utiliser une ViewPagerrotation manuellement ou à l' aide des informations EXIF (90 ° arrêts), remplacer les événements tactiles sélectionnés en utilisant OnClickListenerou votre propre GestureDetectorou OnTouchListener, sous-classe pour ajouter des superpositions, effectuer un panoramique pendant le zoom et lancer l'élan.

Il n'est pas destiné à remplacer une utilisation générale, ImageViewil ne l'étend donc pas et ne prend pas en charge l'affichage d'images à partir de ressources, uniquement des actifs et des fichiers externes. Il nécessite SDK 10.

La source est sur GitHub, et il y a un exemple qui illustre l'utilisation dans a ViewPager.

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

Dave Morrissey
la source
1

Vous pouvez essayer d'utiliser les LayoutParams pour cela

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 (vrai); ZoomOut = zoom (faux);

Noob
la source
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);
        }
    });
}

et le dossier dessinable doit avoir un fichier image bticn. fonctionne parfaitement :)

Muhammad Usman Ghani
la source
0

Quelque chose comme ci-dessous le fera.

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

Pour voir le programme complet, voir ici: Programme pour agrandir l'image dans Android

Animesh Shrivastav
la source