Bagaimana saya bisa mendapatkan fungsionalitas zoom untuk gambar?

204

Apakah ada cara umum untuk menampilkan gambar besar dan memungkinkan pengguna untuk memperbesar dan memperkecil dan menggeser gambar?

Sampai sekarang saya menemukan dua cara:

  1. menimpa ImageView, yang tampaknya sedikit terlalu banyak untuk masalah yang sama.
  2. menggunakan tampilan web tetapi dengan sedikit kontrol atas tata letak keseluruhan dll.
Janusz
sumber
Ada ZOOM CONTROL (Widget) dan Anda dapat mendengarkan acara OnTouch untuk menangani panning.
tobrien
1
Pertanyaan serupa stackoverflow.com/questions/2537396/… , memiliki tautan ke tutorial ini anddev.org/… . Anda mungkin menemukan itu berguna untuk menggeser iamge Anda. Saya belum membacanya secara detail, tetapi mungkin juga memberi Anda beberapa ide tentang bagaimana melakukan fungsi zoom juga.
Steve Haley
Adakah yang mencoba menyimpan gambar saat melakukan zoom? Saya ingin gambar yang disimpan pada keadaan default alih-alih keadaan diperbesar. Silakan lihat pertanyaan saya: stackoverflow.com/questions/24730793/... Terima kasih
Blaze Tama

Jawaban:

208

MEMPERBARUI

Saya baru saja memberi TouchImageView pembaruan baru. Sekarang termasuk Zoom Ketuk Ganda dan Fling selain Panning dan Pinch Zoom. Kode di bawah ini sangat tanggal. Anda dapat memeriksa proyek github untuk mendapatkan kode terbaru.

PEMAKAIAN

Tempatkan TouchImageView.java di proyek Anda. Kemudian dapat digunakan sama dengan ImageView. Contoh:

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

Jika Anda menggunakan TouchImageView dalam xml, maka Anda harus memberikan nama paket lengkap, karena itu adalah tampilan khusus. Contoh:

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

Catatan: Saya telah menghapus jawaban saya sebelumnya, yang mencakup beberapa kode yang sangat lama dan sekarang terhubung langsung ke kode terbaru di github.

ViewPager

Jika Anda tertarik untuk memasukkan TouchImageView dalam ViewPager, lihat jawaban ini.

Mike Ortiz
sumber
4
Paulo, saya tidak mengalami masalah kinerja, tetapi saya tidak bisa menguji pada tablet. Dengan lambat, maksud Anda lamban? Saya menetapkan faktor pembesaran maks 1,05 pada awal onScale. Apakah ini yang sedang Anda bicarakan? Jika tidak, coba yang berikut ini: 1. Apakah Anda dalam mode debug? Ini akan memperlambatnya secara signifikan. 2. Ukuran gambar apa yang Anda atur. Saya tidak menguji dengan gambar yang sangat besar (8mp), tetapi ini mungkin memperlambatnya. 3. Apakah Anda memiliki ponsel yang dapat Anda uji? 4. Jika semuanya gagal, lihat apakah mengalikan mScaleFactor dengan 2 (jika> 1) atau 0,5 (jika <1) membantu situasi Anda.
Mike Ortiz
3
@Ahsan Ubah konstruktor Tampilan ke: TouchImageView(Context context, AttributeSet attrs)dan panggil super(context, attrs);Ini karena ketika Anda mengembang tampilan kustom, itu dibangun dengan dua parameter, bukan hanya satu. Ketika saya menyiasatinya, saya akan memperbaiki TouchImageView untuk mendukung tiga konstruktor tampilan dan drawable.
Mike Ortiz
2
@Ahsan Karena ini adalah tampilan khusus, Anda perlu menuliskan seluruh nama dalam file XML, yaitu <com.example.TouchImageView android:id="@+id/img" />. Apakah kamu melakukan itu?
Mike Ortiz
1
Ini barang bagus, sudah lama mencari ini. Jangan gunakan kode dari github karena lebih baru dan hanya berfungsi lebih baik
Alex
2
@ Mike saya sudah mencoba kode ini tetapi galeri khusus tidak berfungsi. Apakah ada trik untuk mengatasi masalah ini.
Umesh
80

Saya mengadaptasi beberapa kode untuk membuat TouchImageView yang mendukung multitouch (> 2.1). Itu terinspirasi oleh buku Halo, Android! (Edisi ke-3)

Itu terkandung dalam 3 file berikut 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
sumber
Robert Foss, jika ini menambah batas hakim, itu bisa jatuh lebih baik. Terima kasih kodemu dengan baik
pengwang
3
Ini berfungsi, tapi saya tidak mengerti maksudnya WrapMotionEventdan EclairMotionEvent... pokoknya, +1.
Cipi
2
Multitouch untuk ponsel yang mendukungnya. Sentuhan biasa untuk Android <2.0
Robert Foss
Contoh yang bagus itu berfungsi dengan baik tetapi saya tidak mendapatkan apa yang dimaksud dengan Penampil di (Viewer.isDebug == true) {dumpEvent (event); }
Tofeeq Ahmad
2
Apa ini? >> se.robertfoss.ChanImageBrowser.Viewer
emeraldhieu
60

Saya menggunakan WebView dan memuat gambar dari memori melalui

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

WebView menangani semua panning zooming dan scrolling. Jika Anda menggunakan wrap_content tampilan web tidak akan lebih besar maka gambar dan tidak ada area putih ditampilkan. WebView adalah ImageView yang lebih baik;)

Janusz
sumber
5
Saya menggunakan pendekatan yang sama. Saya memiliki peta kereta bawah tanah besar yang saya ingin pengguna dapat memperbesar dan gulirkan. Saya perhatikan bahwa jika Anda memiliki gambar yang cukup besar (yaitu 1000 atau 3000 piksel lebar), gambar menjadi buram setelah Anda memperbesar. Tampaknya coliris tidak dapat menampilkan gambar yang diperbesar sangat tajam. Meskipun gambar aslinya tidak terkompresi dan sangat tajam. Karena itu saya akhirnya memotong satu gambar besar menjadi irisan yang lebih kecil dan menyatukannya kembali melalui HTML. Dengan cara ini gambar tetap tajam saat memperbesar. (Saya menggunakan Nexus One, 2.1perbarui sebelum dan sekarang di 2.2)
Mathias Conradt
@Mathias Lin: jika gambar besar dikirim melalui kawat, saya pernah mendengar operator memampatkan gambar besar. apakah case-use ini cocok untuk Anda atau Anda memuat gambar secara lokal.
Samuel
@Sam Quest: memuatnya secara lokal
Mathias Conradt
4
jauh lebih baik untuk menggunakan tombol zoom bawaan di webview dan mendukung pinch untuk memperbesar / memperkecil daripada menulis algo yang sama sekali baru yang mungkin tidak berfungsi di ponsel yang berbeda dan rilis platform android masa depan
sami
2
solusi ini hanya dapat diterapkan jika Anda kebetulan memiliki gambar duduk di disk, atau gambar cukup kecil sehingga Anda dapat mendasarkan 64 encode adalah dan meneruskan nilai string ke loadUrlWithData ().
Jeffrey Blattman
7

Dalam Respons terhadap pertanyaan awal Janusz, ada beberapa cara untuk mencapai ini yang semuanya bervariasi dalam tingkat kesulitannya dan telah dinyatakan di bawah ini. Menggunakan tampilan web itu bagus, tetapi sangat terbatas dalam hal tampilan dan rasa serta kemampuan kontrol. Jika Anda menggambar bitmap dari kanvas, solusi paling serbaguna yang telah diusulkan tampaknya adalah MikeOrtiz, Robert Foss's dan / atau apa yang disarankan Jacob Nordfalk. Ada contoh yang bagus untuk menggabungkan android-multitouch-controller oleh PaulBourke , dan sangat bagus untuk memiliki dukungan multi-touch dan semua jenis pandangan kustom.

Secara pribadi, jika Anda hanya menggambar kanvas ke bitmap dan kemudian menampilkannya di dalam dan ImageView dan ingin dapat memperbesar dan bergerak menggunakan multi touch, saya menemukan solusi MikeOrtiz sebagai yang termudah. Namun, untuk tujuan saya, kode dari Git yang ia sediakan tampaknya hanya berfungsi ketika kelas TouchImageView kustom ImageView adalah satu-satunya anak atau menyediakan tata letak params seperti:

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

Sayangnya karena desain tata letak saya, saya perlu "wrap_content" untuk "layout_height". Ketika saya mengubahnya ke ini gambar dipotong di bagian bawah dan saya tidak bisa menggulir atau memperbesar ke daerah yang dipotong. Jadi saya melihat Sumber untuk ImageView hanya untuk melihat bagaimana Android menerapkan "onMeasure" dan mengubah MikeOrtiz sesuai.

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

Di sini resolSize (int, int) adalah "Utilitas untuk merekonsiliasi ukuran yang diinginkan dengan batasan yang diberlakukan oleh MeasureSpec, di mana:

Parameter:

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

Pengembalian:

 - The size this view should be."

Jadi intinya memberikan perilaku yang sedikit lebih mirip dengan kelas ImageView asli ketika gambar dimuat. Beberapa perubahan lebih lanjut dapat dilakukan untuk mendukung variasi layar yang lebih besar yang mengubah rasio aspek. Tetapi untuk sekarang saya harap ini membantu. Terima kasih kepada MikeOrtiz untuk kode aslinya, kerja bagus.

digiphd
sumber
Apakah perbaikan ini telah dimasukkan ke dalam repo github Mike?
LarsH
6

Saya baru saja mengintegrasikan TouchImageView Robert Foss: itu bekerja dengan baik di luar kotak! Terima kasih!

Saya baru saja memodifikasi sedikit kode sehingga saya bisa dapat instantiate dari layout.xml saya.

Cukup tambahkan dua konstruktor

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

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

dan mengubah konstruktor lama menjadi metode init:

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

@Robert Foss, @Mike Ortiz, terima kasih banyak atas pekerjaan Anda. Saya menggabungkan pekerjaan Anda, dan menyelesaikan kelas Robert untuk android> 2.0 dengan pekerjaan tambahan Mike.

Sebagai hasil dari pekerjaan saya, saya menghadirkan Android Touch Gallery, berdasarkan pada ViewPager dan menggunakan TouchImageView yang dimodifikasi. Gambar memuat dengan URL dan Anda dapat memperbesar dan menariknya. Anda dapat menemukannya di sini https://github.com/Dreddik/AndroidTouchGallery

Roman Truba
sumber
2

Coba gunakan ZoomView untuk memperbesar tampilan lainnya.

http://code.google.com/p/android-zoom-view/ mudah, gratis, dan menyenangkan untuk digunakan!

karooolek
sumber
Repositori ini tidak lagi dipertahankan.
erginduran
2

Menambahkan ke jawaban @ Mike. Saya juga perlu ketuk dua kali untuk mengembalikan gambar ke dimensi asli saat pertama kali dilihat. Jadi saya menambahkan seluruh tumpukan variabel instance "orig ..." dan menambahkan SimpleOnGestureListener yang melakukan trik.

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

Ini adalah tambahan yang sangat terlambat untuk utas ini tetapi saya telah mengerjakan tampilan gambar yang mendukung zoom dan pan dan memiliki beberapa fitur yang belum saya temukan di tempat lain. Ini dimulai sebagai cara untuk menampilkan gambar yang sangat besar tanpa menyebabkan OutOfMemoryError, dengan subsampling gambar ketika diperbesar dan memuat ubin resolusi lebih tinggi ketika diperbesar. Sekarang mendukung penggunaan dalam ViewPager, rotasi secara manual atau menggunakan informasi EXIF ​​(berhenti 90 °), menimpa acara sentuh yang dipilih menggunakan OnClickListeneratau subclassing Anda sendiri GestureDetectoratau OnTouchListener, untuk menambahkan overlay, menggeser sambil memperbesar, dan melemparkan momentum.

Ini tidak dimaksudkan sebagai pengganti penggunaan umum untuk ImageViewjadi tidak memperluasnya, dan tidak mendukung tampilan gambar dari sumber daya, hanya aset dan file eksternal. Ini membutuhkan SDK 10.

Sumber ada di GitHub, dan ada contoh yang menggambarkan penggunaan di a ViewPager .

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

Dave Morrissey
sumber
1

Anda dapat mencoba menggunakan LayoutParams untuk ini

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 (benar); ZoomOut = zoom (salah);

cupu
sumber
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);
        }
    });
}

dan folder yang dapat digambar harus memiliki file gambar bticn. bekerja dengan sempurna :)

Muhammad Usman Ghani
sumber
0

Sesuatu seperti di bawah ini akan melakukannya.

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

Untuk melihat program lengkap, lihat di sini: Program untuk memperbesar gambar di android

Animesh Shrivastav
sumber