Jak mogę uzyskać funkcję powiększania obrazów?

204

Czy istnieje wspólny sposób wyświetlania dużego obrazu i umożliwiania użytkownikowi powiększania i pomniejszania oraz przesuwania obrazu?

Do tej pory znalazłem dwa sposoby:

  1. nadpisując ImageView, wydaje się to trochę za dużo jak na tak powszechny problem.
  2. używając widoku internetowego, ale z mniejszą kontrolą nad ogólnym układem itp.
Janusz
źródło
Istnieje ZOOM CONTROL (widget) i możesz słuchać zdarzenia OnTouch, aby obsłużyć panoramowanie.
tobrien
1
Podobne pytanie stackoverflow.com/questions/2537396/... , zawiera link do tego samouczka idev.org/… . Może się to przydać do przesuwania iamge. Nie przeczytałem go szczegółowo, ale może również dać ci kilka pomysłów, jak wykonać funkcję powiększenia.
Steve Haley
Czy ktoś próbował zapisać obraz podczas powiększania? Chcę, aby zapisany obraz był w stanie domyślnym zamiast w stanie powiększonym. Proszę zobaczyć moje pytanie: stackoverflow.com/questions/24730793/... Dzięki
Blaze Tama

Odpowiedzi:

208

AKTUALIZACJA

Właśnie podałem TouchImageView nową aktualizację. Obejmuje teraz powiększanie podwójnym dotknięciem i rzutowanie oprócz powiększania panoramy i powiększania. Poniższy kod jest bardzo stary. Możesz sprawdzić projekt github, aby uzyskać najnowszy kod.

STOSOWANIE

Umieść TouchImageView.java w swoim projekcie. Następnie można go używać tak samo jak ImageView. Przykład:

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

Jeśli używasz TouchImageView w formacie xml, musisz podać pełną nazwę pakietu, ponieważ jest to widok niestandardowy. Przykład:

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

Uwaga: usunąłem moją poprzednią odpowiedź, która zawierała bardzo stary kod i teraz link do najbardziej aktualnego kodu na github.

ViewPager

Jeśli chcesz umieścić TouchImageView w ViewPager, zapoznaj się z tą odpowiedzią.

Mike Ortiz
źródło
4
Paulo, nie napotkałem problemów z wydajnością, ale nie dostałem testu na tablecie. Przez powolność masz na myśli lagi? Ustawiłem maksymalny współczynnik powiększenia na 1,05 na początku skali. Czy o tym mówisz? Jeśli nie, spróbuj wykonać następujące czynności: 1. Czy jesteś w trybie debugowania? Spowolniłoby to znacznie. 2. Jaki rozmiar zdjęć ustawiasz. Nie testowałem z bardzo dużymi obrazami (8mp), ale może to spowolnić. 3. Czy masz telefon, na którym możesz przetestować? 4. Jeśli wszystko inne zawiedzie, sprawdź, czy pomnożenie mScaleFactor przez 2 (jeśli> 1) lub 0,5 (jeśli <1) pomaga w twojej sytuacji.
Mike Ortiz
3
@Ahsan Zmień konstruktor widoku na: TouchImageView(Context context, AttributeSet attrs)i wywołaj super(context, attrs);Wynika to z tego, że po nadmuchaniu widoku niestandardowego jest on konstruowany przy użyciu dwóch parametrów, a nie tylko jednego. Kiedy do tego dojdę, naprawię TouchImageView, aby obsługiwał trzy konstruktory widoków i drawable.
Mike Ortiz
2
@Ahsan Ponieważ jest to widok niestandardowy, musisz zapisać całą nazwę w pliku XML, tj <com.example.TouchImageView android:id="@+id/img" />. Czy ty to zrobiłeś?
Mike Ortiz
1
To świetne rzeczy, szukałem tego od wieków. Używaj kodu z github, ponieważ jest on nowszy i po prostu działa lepiej
Alex
2
@Mike próbowałem tego kodu, ale galeria niestandardowa nie działa. Czy istnieje jakiś sposób obejścia tego problemu?
Umesh,
80

Dostosowałem trochę kodu, aby utworzyć TouchImageView, który obsługuje multitouch (> 2.1). Inspiruje się książką Hello, Android! (3. edycja)

Jest zawarty w następujących 3 plikach 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
źródło
Robert Foss, jeśli dodasz sędziego granicznego, może on spaść lepiej. Dziękuję bardzo dobrze
kodowi
3
Działa, ale nie widzę sensu WrapMotionEventi EclairMotionEvent... w każdym razie +1.
Cipi
2
Multitouch dla telefonów, które go obsługują. Regularny dotyk dla Androida <2.0
Robert Foss
Fajny przykład działa dobrze, ale nie dostałem, co to jest Viewer, jeśli (Viewer.isDebug == true) {dumpEvent (event); }
Tofeeq Ahmad
2
Co to jest? >> se.robertfoss.ChanImageBrowser.Viewer
emeraldhieu
60

Użyłem WebView i załadowałem obraz z pamięci przez

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

WebView obsługuje wszystkie powiększanie i przewijanie panoramowania. Jeśli użyjesz wrap_content, widok nie będzie większy niż obraz i nie zostaną wyświetlone białe obszary. WebView to lepszy ImageView;)

Janusz
źródło
5
Używam tego samego podejścia. Mam dużą mapę metra, którą chcę, aby użytkownik mógł powiększać i przewijać. Zauważyłem jednak, że jeśli masz dość duży obraz (tj. 1000 lub 3000 pikseli szerokości), obraz staje się rozmyty po powiększeniu. Wygląda na to, że coliris nie może wyświetlać dużego powiększonego obrazu bardzo ostro. Mimo że oryginalny obraz jest nieskompresowany i bardzo ostry. Dlatego skończyło się na pocięciu jednego dużego obrazu na mniejsze plasterki i ponownym złożeniu ich za pomocą HTML. W ten sposób obraz pozostaje ostry podczas powiększania. (Jestem na Nexus One, aktualizacja 2.1 wcześniej, a teraz 2.2)
Mathias Conradt
@Mathias Lin: jeśli duży obraz jest przesyłany przewodowo, słyszałem, że operatorzy kompresują duże obrazy. czy ten przypadek użycia będzie ci odpowiadał lub czy obraz został załadowany lokalnie.
Samuel
@Sam Quest: ładowanie lokalne
Mathias Conradt
4
o wiele lepiej jest korzystać z wbudowanych przycisków zoomu w przeglądarce internetowej i obsługi szczypania w celu powiększania / pomniejszania, niż pisać zupełnie nowe algo, które może nie działać na różnych telefonach i przyszłych wydaniach platformy Android
sami
2
to rozwiązanie można zastosować tylko wtedy, gdy zdarza się, że obraz siedzi na dysku lub obraz jest na tyle mały, że można bazować na 64 kodowanie i przekazać wartość ciągu do loadUrlWithData ().
Jeffrey Blattman,
7

W odpowiedzi na oryginalne pytanie Janusza istnieje kilka sposobów na osiągnięcie tego celu, z których każdy różni się poziomem trudności i został opisany poniżej. Korzystanie z widoku internetowego jest dobre, ale jest bardzo ograniczone pod względem wyglądu, dotyku i kontroli. Jeśli rysujesz mapę bitową z płótna, najbardziej wszechstronnymi zaproponowanymi rozwiązaniami wydają się rozwiązania MikeOrtiza, Roberta Fossa i / lub sugestie Jacoba Nordfalka. Jest świetny przykład włączenia kontrolera wielodotykowego Androida autorstwa PaulBourke i doskonale nadaje się do obsługi wielodotyku i wszelkiego rodzaju niestandardowych widoków.

Osobiście, jeśli po prostu rysujesz płótno na mapie bitowej, a następnie wyświetlasz je wewnątrz i ImageView i chcesz móc powiększać i przemieszczać się za pomocą multi-touch, uważam rozwiązanie MikeOrtiz za najłatwiejsze. Jednak dla moich celów kod z Git , który podał, wydaje się działać tylko wtedy, gdy jego niestandardowa klasa ImageView TouchImageView jest jedynym dzieckiem lub podaje parametry układu jako:

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

Niestety z powodu mojego projektu układu potrzebowałem „wrap_content” dla „layout_height”. Kiedy zmieniłem to na to obraz został przycięty na dole i nie mogłem przewinąć ani powiększyć obszaru przycięcia. Spojrzałem więc na Source for ImageView, aby zobaczyć, jak Android zaimplementował „onMeasure” i zmienił MikeOrtiza na odpowiedni.

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

Tutaj resolSize (int, int) to „Narzędzie do uzgadniania pożądanego rozmiaru z ograniczeniami narzuconymi przez MeasureSpec, gdzie:

Parametry:

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

Zwroty:

 - The size this view should be."

Zasadniczo zapewnia zachowanie nieco bardziej podobne do oryginalnej klasy ImageView po załadowaniu obrazu. Można wprowadzić więcej zmian, aby obsługiwać większą różnorodność ekranów, które modyfikują proporcje obrazu. Ale na razie mam nadzieję, że to pomaga. Dzięki MikeOrtiz za jego oryginalny kod, świetna robota.

digiphd
źródło
Czy ta poprawka została uwzględniona w repozytorium github Mike'a?
LarsH
6

Właśnie zintegrowałem TouchImageView Roberta Fossa: zadziałał doskonale po wyjęciu z pudełka! Dzięki!

Właśnie zmodyfikowałem trochę kod, aby móc utworzyć jego instancję z pliku layout.xml.

Po prostu dodaj dwa konstruktory

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

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

i przekształć starego konstruktora w metodę init:

private void init(Context context){
    //...old code ofconstructor of Robert Moss's code
}
zontar
źródło
3

@Robert Foss, @Mike Ortiz, bardzo dziękuję za twoją pracę. Połączyłem twoją pracę i ukończyłem klasy Roberta dla Androida> 2.0 z dodatkowymi pracami Mike'a.

W wyniku mojej pracy prezentuję Galerię dotykową Android, opartą na ViewPager i wykorzystującą zmodyfikowany TouchImageView. Obrazy ładują się według adresu URL i możesz je powiększać i przeciągać. Można go znaleźć tutaj https://github.com/Dreddik/AndroidTouchGallery

Roman Truba
źródło
2

Spróbuj użyć ZoomViewdo powiększenia dowolnego innego widoku.

http://code.google.com/p/android-zoom-view/ jest łatwy, darmowy i przyjemny w użyciu!

karooolek
źródło
To repozytorium nie jest już utrzymywane.
erginduran
2

Dodanie do odpowiedzi @ Mike'a. Potrzebowałem też podwójnego stuknięcia, aby przywrócić obraz do oryginalnych wymiarów podczas pierwszego oglądania. Więc dodałem całą masę zmiennych instancji „orig ...” i dodałem SimpleOnGestureListener, który załatwił sprawę.

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
źródło
2

Jest to bardzo późny dodatek do tego wątku, ale pracowałem nad widokiem obrazu, który obsługuje powiększanie i przesuwanie i ma kilka funkcji, których nie znalazłem gdzie indziej. Zaczęło się to od sposobu wyświetlania bardzo dużych obrazów bez powodowania OutOfMemoryErrors, poprzez podpróbkowanie obrazu po pomniejszeniu i ładowanie kafelków o wyższej rozdzielczości po powiększeniu. Teraz obsługuje ViewPagerręczne obracanie lub użycie informacji EXIF ​​(90 stopni zatrzymuje), zastępuj wybrane zdarzenia dotykowe za pomocą OnClickListenerlub własnego GestureDetectorlub OnTouchListener, podklasy, aby dodać nakładki, przesuwać podczas powiększania i pędu.

Nie jest przeznaczony do ogólnego zastępowania, ImageViewwięc go nie rozszerza i nie obsługuje wyświetlania obrazów z zasobów, tylko zasobów i plików zewnętrznych. Wymaga zestawu SDK 10.

Źródło znajduje się na GitHub, a jest tam próbka ilustrująca użycie w ViewPager.

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

Dave Morrissey
źródło
1

Możesz w tym celu spróbować użyć LayoutParams

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

Nowicjusz
źródło
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);
        }
    });
}

a folder do rysowania powinien mieć plik obrazu bticn. doskonale działa :)

Muhammad Usman Ghani
źródło
0

Zrobi to coś takiego jak poniżej.

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

Aby wyświetlić pełny program, zobacz tutaj: Program do powiększania obrazu w Androidzie

Animesh Shrivastav
źródło