Wie kann ich Zoomfunktionen für Bilder erhalten?

204

Gibt es eine übliche Möglichkeit, ein großes Bild anzuzeigen und dem Benutzer das Vergrößern und Verkleinern sowie das Schwenken des Bildes zu ermöglichen?

Bis jetzt habe ich zwei Wege gefunden:

  1. Das Überschreiben von ImageView scheint für ein so häufiges Problem etwas zu viel zu sein.
  2. Verwenden einer Webansicht, jedoch mit weniger Kontrolle über das Gesamtlayout usw.
Janusz
quelle
Es gibt eine ZOOM-STEUERUNG (Widget) und Sie können das OnTouch-Ereignis anhören, um das Schwenken durchzuführen.
Tobien
1
Eine ähnliche Frage stackoverflow.com/questions/2537396/… enthält einen Link zu diesem Tutorial anddev.org/… . Vielleicht finden Sie das nützlich, um Ihr iamge zu schwenken. Ich habe es nicht im Detail gelesen, aber es könnte Ihnen auch einige Ideen geben, wie Sie die Zoomfunktion ausführen können.
Steve Haley
Hat jemand versucht, das Bild beim Zoomen zu speichern? Ich möchte, dass das gespeicherte Bild in einem Standardzustand anstelle des gezoomten Zustands angezeigt wird. Bitte sehen Sie meine Frage: stackoverflow.com/questions/24730793/… Danke
Blaze Tama

Antworten:

208

AKTUALISIEREN

Ich habe TouchImageView gerade ein neues Update gegeben. Es enthält jetzt zusätzlich zu Panning und Pinch Zoom Double Tap Zoom und Fling. Der folgende Code ist sehr veraltet. Sie können das Github-Projekt überprüfen, um den neuesten Code zu erhalten.

VERWENDUNG

Platzieren Sie TouchImageView.java in Ihrem Projekt. Es kann dann genauso wie ImageView verwendet werden. Beispiel:

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

Wenn Sie TouchImageView in XML verwenden, müssen Sie den vollständigen Paketnamen angeben, da es sich um eine benutzerdefinierte Ansicht handelt. Beispiel:

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

Hinweis: Ich habe meine vorherige Antwort entfernt, die einen sehr alten Code enthielt, und verweise jetzt direkt auf den aktuellsten Code auf Github.

ViewPager

Wenn Sie TouchImageView in einen ViewPager einfügen möchten, lesen Sie diese Antwort.

Mike Ortiz
quelle
4
Paulo, ich hatte keine Leistungsprobleme, konnte aber nicht auf einem Tablet testen. Mit langsam meinst du laggy? Ich habe zu Beginn von onScale einen maximalen Zoomfaktor von 1,05 eingestellt. Redest du das? Wenn nicht, versuchen Sie Folgendes: 1. Befinden Sie sich im Debug-Modus? Dies würde es erheblich verlangsamen. 2. Welche Bildgröße stellen Sie ein? Ich habe nicht mit sehr großen (8 MP) Bildern getestet, aber dies könnte es verlangsamen. 3. Haben Sie ein Telefon, auf dem Sie testen können? 4. Wenn alles andere fehlschlägt, prüfen Sie, ob das Multiplizieren von mScaleFactor mit 2 (wenn> 1) oder 0,5 (wenn <1) Ihrer Situation hilft.
Mike Ortiz
3
@Ahsan Ändern Sie den View-Konstruktor in: TouchImageView(Context context, AttributeSet attrs)und rufen Sie auf. super(context, attrs);Dies liegt daran, dass beim Aufblasen der benutzerdefinierten Ansicht nicht nur einer, sondern zwei Parameter verwendet werden. Wenn ich dazu komme, werde ich TouchImageView reparieren, um die drei Ansichtskonstruktoren und Drawables zu unterstützen.
Mike Ortiz
2
@Ahsan Da es sich um eine benutzerdefinierte Ansicht handelt, müssen Sie den gesamten Namen in die XML-Datei schreiben, d <com.example.TouchImageView android:id="@+id/img" />. H. Hast du das gemacht?
Mike Ortiz
1
Das ist großartiges Zeug, das schon seit Ewigkeiten gesucht wird. Verwenden Sie den Code von Github, da er neuer ist und einfach besser funktioniert
Alex
2
@ Mike Ich habe diesen Code ausprobiert, aber die benutzerdefinierte Galerie funktioniert nicht. Gibt es einen Trick, um dieses Problem zu umgehen?
Umesh
80

Ich habe Code angepasst, um eine TouchImageView zu erstellen, die Multitouch unterstützt (> 2.1). Es ist inspiriert von dem Buch Hallo, Android! (3. Auflage)

Es ist in den folgenden 3 Dateien enthalten: 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
quelle
Robert Foss, wenn dieser Grenzrichter hinzufügt, kann es besser fallen. Vielen Dank für Ihren Code
Pengwang
3
Es funktioniert, aber ich sehe den Punkt nicht in WrapMotionEventund EclairMotionEvent... sowieso +1.
Cipi
2
Multitouch für Telefone, die dies unterstützen. Ein regelmäßiger Touch für Android <2.0
Robert Foss
Schönes Beispiel, es funktioniert gut, aber ich habe nicht verstanden, in was Viewer ist, wenn (Viewer.isDebug == true) {dumpEvent (Ereignis); }
Tofeeq Ahmad
2
Was ist das? >> se.robertfoss.ChanImageBrowser.Viewer
emeraldhieu
60

Ich habe ein WebView verwendet und das Bild über aus dem Speicher geladen

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

Das WebView übernimmt das gesamte Zoomen und Scrollen des Schwenks. Wenn Sie wrap_content verwenden, wird die Webansicht nicht größer als das Bild und es werden keine weißen Bereiche angezeigt. Das WebView ist das bessere ImageView;)

Janusz
quelle
5
Ich benutze den gleichen Ansatz. Ich habe eine große U-Bahn-Karte, auf der der Benutzer zoomen und scrollen kann. Mir ist jedoch aufgefallen, dass bei einem ziemlich großen Bild (dh 1000 oder 3000 Pixel breit) das Bild beim Vergrößern unscharf wird. Es scheint, dass Coliris ein großes gezoomtes Bild nicht sehr scharf anzeigen kann. Obwohl das Originalbild unkomprimiert und sehr scharf ist. Deshalb habe ich das eine große Bild in kleinere Scheiben geschnitten und sie über HTML wieder zusammengesetzt. Auf diese Weise bleibt das Bild beim Vergrößern scharf. (Ich bin auf Nexus One, 2.1update vor und jetzt auf 2.2)
Mathias Conradt
@ Mathias Lin: Wenn ein großes Bild über das Kabel gesendet wird, habe ich gehört, dass Träger große Bilder komprimieren. Wird dieser Anwendungsfall zu Ihnen passen oder haben Sie das Bild lokal geladen?
Samuel
@ Sam Quest: Laden Sie es lokal
Mathias Conradt
4
Es ist viel besser, die in Webview integrierten Zoomtasten und die Unterstützung für das Vergrößern / Verkleinern zu verwenden, als ein völlig neues Algo zu schreiben, das möglicherweise nicht auf verschiedenen Handys und zukünftigen Versionen der Android-Plattform funktioniert
sami
2
Diese Lösung kann nur angewendet werden, wenn sich das Image zufällig auf der Festplatte befindet oder das Image so klein ist, dass Sie die 64er-Codierung verwenden und den Zeichenfolgenwert an loadUrlWithData () übergeben können.
Jeffrey Blattman
7

Als Antwort auf die ursprüngliche Frage von Janusz gibt es verschiedene Möglichkeiten, dies zu erreichen, die sich alle in ihrem Schwierigkeitsgrad unterscheiden und nachstehend aufgeführt sind. Die Verwendung einer Webansicht ist gut, jedoch in Bezug auf Erscheinungsbild und Steuerbarkeit sehr eingeschränkt. Wenn Sie eine Bitmap von einer Leinwand zeichnen, scheinen die vielseitigsten Lösungen, die vorgeschlagen wurden, die von MikeOrtiz, Robert Foss und / oder das zu sein, was Jacob Nordfalk vorgeschlagen hat. Es gibt ein gutes Beispiel für die Integration des Android-Multitouch-Controllers von PaulBourke und die Multitouch-Unterstützung und alle Arten von benutzerdefinierten Ansichten.

Persönlich finde ich die Lösung von MikeOrtiz am einfachsten, wenn Sie einfach eine Leinwand auf eine Bitmap zeichnen und sie dann in ImageView anzeigen und in der Lage sind, mit Multi-Touch hineinzuzoomen und sich zu bewegen. Für meine Zwecke scheint der von ihm bereitgestellte Code aus dem Git jedoch nur zu funktionieren, wenn seine benutzerdefinierte ImageIiew-Klasse TouchImageView das einzige untergeordnete Element ist oder die Layoutparameter wie folgt bereitstellt:

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

Leider brauchte ich aufgrund meines Layoutdesigns "wrap_content" für "layout_height". Als ich dies änderte, wurde das Bild unten zugeschnitten und ich konnte nicht in den zugeschnittenen Bereich scrollen oder zoomen. Also habe ich mir die Quelle für ImageView angesehen, um zu sehen, wie Android "onMeasure" implementiert und MikeOrtiz entsprechend angepasst hat.

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

Hier ist resolveSize (int, int) ein "Dienstprogramm zum Abgleichen einer gewünschten Größe mit Einschränkungen, die durch eine MeasureSpec auferlegt werden, wobei:

Parameter:

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

Kehrt zurück:

 - The size this view should be."

Stellen Sie also im Wesentlichen ein Verhalten bereit, das der ursprünglichen ImageView-Klasse beim Laden des Bildes etwas ähnlicher ist. Es könnten weitere Änderungen vorgenommen werden, um eine größere Auswahl an Bildschirmen zu unterstützen, die das Seitenverhältnis ändern. Aber jetzt hoffe ich, dass dies hilft. Vielen Dank an MikeOrtiz für seinen ursprünglichen Code, großartige Arbeit.

digiphd
quelle
Wurde dieses Update in Mikes Github-Repo aufgenommen?
LarsH
6

Ich habe gerade Robert Foss 'TouchImageView integriert: Es hat sofort funktioniert! Vielen Dank!

Ich habe den Code nur ein wenig geändert, damit ich ihn aus meiner layout.xml instanziieren kann.

Fügen Sie einfach zwei Konstruktoren hinzu

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

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

und transformieren Sie den alten Konstruktor in eine init-Methode:

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

@ Robert Foss, @ Mike Ortiz, vielen Dank für Ihre Arbeit. Ich habe Ihre Arbeit zusammengeführt und Robert-Kurse für Android> 2.0 mit Mike zusätzlicher Arbeit abgeschlossen.

Als Ergebnis meiner Arbeit präsentiere ich die Android Touch Gallery, die auf ViewPager basiert und modifiziertes TouchImageView verwendet. Bilder werden per URL geladen und können gezoomt und gezogen werden. Sie finden es hier https://github.com/Dreddik/AndroidTouchGallery

Römische Truba
quelle
2

Versuchen Sie, ZoomVieweine andere Ansicht zum Zoomen zu verwenden.

http://code.google.com/p/android-zoom-view/ es ist einfach, kostenlos und macht Spaß!

Karooolek
quelle
Dieses Repository wird nicht mehr verwaltet.
Erginduran
2

Hinzufügen zu @ Mikes Antwort. Ich musste auch zweimal tippen, um das Bild beim ersten Betrachten auf die ursprünglichen Abmessungen zurückzusetzen. Also habe ich einen ganzen Haufen "orig ..." - Instanzvariablen hinzugefügt und den SimpleOnGestureListener hinzugefügt, der den Trick gemacht hat.

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
quelle
2

Dies ist eine sehr späte Ergänzung zu diesem Thread, aber ich habe an einer Bildansicht gearbeitet, die Zoom und Schwenken unterstützt und einige Funktionen enthält, die ich anderswo nicht gefunden habe. Dies begann damit, sehr große Bilder anzuzeigen, ohne OutOfMemoryErrors zu verursachen , indem das Bild beim Verkleinern unterabgetastet und beim Vergrößern Kacheln mit höherer Auflösung geladen wurden. Es unterstützt jetzt die Verwendung in a ViewPager, die manuelle Drehung oder die Verwendung von EXIF-Informationen (90 ° -Stopps). Überschreiben ausgewählter Berührungsereignisse mit OnClickListeneroder Ihrem eigenen GestureDetectoroderOnTouchListener Unterklasse zum Hinzufügen von Überlagerungen, Schwenken beim Zoomen und Schwingen des Impulses.

Es ist nicht als allgemeiner Ersatz für gedacht ImageView erweitert es also nicht und unterstützt nicht die Anzeige von Bildern aus Ressourcen, nur Assets und externen Dateien. Es erfordert SDK 10.

Die Quelle befindet sich auf GitHub, und es gibt ein Beispiel, das die Verwendung in a veranschaulicht ViewPager.

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

Dave Morrissey
quelle
1

Sie können versuchen, die LayoutParams dafür zu verwenden

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 (wahr); ZoomOut = zoom (false);

Anfänger
quelle
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);
        }
    });
}

und zeichnbarer Ordner sollte bticn Bilddatei haben. funktioniert perfekt :)

Muhammad Usman Ghani
quelle
0

So etwas wie unten wird es tun.

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

Das vollständige Programm finden Sie hier: Programm zum Zoomen von Bildern in Android

Animesh Shrivastav
quelle