Як отримати функцію збільшення зображення?


204

Чи є загальний спосіб показати велике зображення та дозволити користувачеві збільшувати та зменшувати розмір та панорамировать зображення?

До цих пір я знайшов два способи:

  1. перезапис ImageView, що здається трохи забагато для такої поширеної проблеми.
  2. за допомогою веб-перегляду, але з меншим контролем над загальним макетом тощо.

Існує КОНТРОЛЬ ЗООМ (віджет), і ви можете прослухати подію OnTouch, щоб обробити панування.
тобріен

1
Аналогічне запитання stackoverflow.com/questions/2537396/… , має посилання на цей підручник anddev.org/… . Можливо, вам це стане в нагоді для панорами вашої iamge. Я не читав його докладно, але це також може дати вам кілька ідей, як зробити функцію збільшення.
Стів Хейлі

Хтось намагався зберегти зображення під час збільшення? Я хочу, щоб збережене зображення було за умовчанням замість масштабуваного. Будь ласка, подивіться на моє запитання: stackoverflow.com/questions/24730793/… Дякую
Blaze Tama

Відповіді:


208

ОНОВЛЕННЯ

Я щойно дав TouchImageView нове оновлення. Тепер він включає подвійний зум та зусилля Fling на додаток до панорамування та масштабування. Код нижче дуже датований. Ви можете перевірити проект github, щоб отримати останній код.

ВИКОРИСТАННЯ

Розмістіть TouchImageView.java у своєму проекті. Потім він може бути використаний так само, як ImageView. Приклад:

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

Якщо ви використовуєте TouchImageView в xml, ви повинні вказати повне ім'я пакета, оскільки це спеціальний вид. Приклад:

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

Примітка. Я видалив попередню відповідь, яка включала в себе дуже старий код і тепер посилається прямо на самий оновлений код на github.

ViewPager

Якщо ви зацікавлені в тому, щоб помістити TouchImageView в ViewPager, зверніться до цієї відповіді.


4
Пауло, я не стикався з проблемами продуктивності, але не взяв тест на планшет. Під повільним, ви маєте на увазі відставання? Я встановив максимальний коефіцієнт збільшення 1,05 на початку onScale. Це те, про що ти говориш? Якщо ні, спробуйте наступне: 1. Ви перебуваєте в режимі налагодження? Це значно уповільнить його. 2. Які розміри зображень ви встановлюєте. Я не тестував із дуже великими (8-кратними) зображеннями, але це може сповільнити його. 3. У вас є телефон, на який ви могли б протестувати? 4. Якщо все інше не вдається, подивіться, чи множення mScaleFactor на 2 (якщо> 1) або 0,5 (якщо <1) допомагає вашій ситуації.
Майк Ортіз

3
@Ahsan Змініть конструктор View на: TouchImageView(Context context, AttributeSet attrs)і зателефонуйте super(context, attrs);Це тому, що коли ви надуваєте нестандартний вигляд, він складається з двох параметрів, а не лише одного. Коли я обійдусь цим, я зафіксую TouchImageView, щоб підтримувати три конструктори та малюнки.
Майк Ортіз

2
@Ahsan Оскільки це власний вигляд, вам потрібно виписати ціле ім’я у XML-файл, тобто <com.example.TouchImageView android:id="@+id/img" />. Ти це робив?
Майк Ортіз

1
Це чудові речі, шукали це протягом століть. Скористайтеся кодом від github, оскільки він є останнім часом і просто працює краще
Alex

2
@Mike Я спробував цей код, але спеціальна галерея не працює. Чи є якась хитрість вирішення цієї проблеми.
Умеш

80

Я адаптував деякий код, щоб створити TouchImageView, який підтримує мультитач (> 2.1). Він натхненний книгою Привіт, Android! (3-е видання)

Він міститься в наступних 3 файлах 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);
    }
}

Роберт Фосс, якщо додати граничні суддя, він може упав більш well.thank вам код дуже добре
pengwang

3
Це працює, але я не бачу сенсу WrapMotionEventі EclairMotionEvent... все одно, +1.
Cipi

2
Мультитач для телефонів, які його підтримують. Черговий штрих для Android <2.0
Роберт Фосс

Хороший приклад, він працює добре, але я не отримав, що є Viewer, якщо (Viewer.isDebug == true) {dumpEvent (подія); }
Tofeeq Ahmad

2
Що це? >> se.robertfoss.ChanImageBrowser.Viewer
смарагдовий

60

Я використовував WebView і завантажував зображення із пам'яті через

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

WebView обробляє все панорамування масштабування та прокрутки. Якщо ви використовуєте wrap_content, перегляд веб-сторінки не буде більшим, ніж зображення, а білі області не відображаються. WebView - тим кращий ImageView;)


5
Я використовую той самий підхід. У мене є велика карта метро, ​​за якою я хочу, щоб користувач міг збільшувати масштаб і прокручувати навколо себе. Я помітив, що якщо у вас досить велике зображення (тобто 1000 або 3000 пікселів у ширину), зображення стає розмитим, коли ви збільшуєте зображення. Здається, колис не може відображати велике збільшене зображення дуже чітко. Навіть незважаючи на те, що оригінальне зображення не стиснене і дуже різке. Тому я нарешті вирізав одне велике зображення на менші фрагменти і знову з’єднав їх за допомогою HTML. Таким чином зображення залишається різким при збільшенні. (Я на Nexus One, 2.1 оновлення до цього часу і зараз на 2.2)
Mathias Conradt

@Mathias Lin: якщо велике зображення надсилається по дроту, я чув, що носії стискають великі зображення. чи підійде вам цей футляр чи ви завантажили зображення локально.
Самуїл

@Sam Quest: завантажується локально
Матіас Конрадт

4
набагато краще використовувати вбудовані кнопки збільшення для веб-перегляду та підтримку прищепки для збільшення / зменшення масштабів, ніж писати абсолютно нове альго, яке може не працювати на різних телефонах та майбутніх релізах платформи Android
самі

2
це рішення можна застосувати, лише якщо у вас є зображення, яке сидить навколо на диску, або зображення є досить малим, щоб ви могли базувати 64 кодування і передавати значення рядка в loadUrlWithData ().
Джефрі Блатман

7

У відповідь на оригінальне запитання Януша існує декілька способів досягти цього, всі вони різняться за рівнем складності та були описані нижче. Використання веб-перегляду - це добре, але дуже обмежено з точки зору зовнішнього вигляду та відчуття та керованості. Якщо ви малюєте растрову карту з полотна, найбільш універсальними рішеннями, які були запропоновані, є такі, як MikeOrtiz, Роберт Фосс та / або те, що запропонував Джейкоб Нордфальк. Є чудовий приклад включення Android-мультитач-контролера від PaulBourke , і чудово підходить для підтримки мультитач і всіх типів користувацьких поглядів.

Особисто, якщо ви просто малюєте полотно до растрової карти, а потім показуєте її всередині та ImageView і хочете мати змогу збільшувати масштаби та переміщуватися за допомогою мультитач, я вважаю рішення MikeOrtiz як найпростіше. Однак, для моїх цілей код з наданого ним Git , здається, працює лише тоді, коли його користувальницький клас ImageView TouchImageView є єдиним дочірнім або надають параметри компонування як:

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

На жаль, завдяки моєму дизайну верстки мені знадобився "wrap_content" для "layout_height". Коли я змінив це на це, зображення було обрізано внизу, і я не міг прокручувати або збільшувати масштаб на обрізану область. Тому я подивився на Джерело для ImageView, щоб побачити, як Android реалізував "onMeasure" та змінив MikeOrtiz на відповідний.

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

Тут resolutionSize (int, int) - це "Утиліта для узгодження потрібного розміру з обмеженнями, накладеними MeasureSpec, де:

Параметри:

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

Повернення:

 - The size this view should be."

Тож по суті надає поведінку трохи більше схожою на початковий клас ImageView при завантаженні зображення. Ще кілька змін можна зробити для підтримки більшої кількості екранів, які змінюють співвідношення сторін. Але наразі сподіваюся, що це допомагає. Завдяки MikeOrtiz за його оригінальний код, чудова робота.


Чи було це виправлення включено у ретро-реліз Майка?
LarsH


6

Я щойно вбудував TouchImageView Роберта Фосса: він прекрасно працював! Дякую!

Я просто змінив трохи коду, щоб я міг створити його з мого layout.xml.

Просто додайте два конструктори

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

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

і перетворити старий конструктор в метод init:

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

3

@Robert Foss, @Mike Ortiz, дуже дякую за вашу роботу. Я з’єднав вашу роботу і закінчив Роберт-класи для android> 2.0 з додатковою роботою Майка.

В результаті своєї роботи я представляю Android Touch Gallery, засновану на ViewPager та використаний модифікований TouchImageView. Завантаження зображень за URL-адресою, і ви можете їх збільшувати та перетягувати. Ви можете знайти його тут https://github.com/Dreddik/AndroidTouchGallery



2

Додавання до відповіді @ Майка. Також мені знадобилося подвійне торкання, щоб відновити зображення до початкових розмірів при першому перегляді. Тому я додав цілу купу змінних екземплярів "orig ..." і додав SimpleOnGestureListener, який зробив трюк.

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

}

2

Це дуже пізнє доповнення до цієї теми, але я працював над поданням зображення, яке підтримує масштабування та панорамування, і має кілька функцій, яких я не знайшов в іншому місці. Це почалося як спосіб відображення дуже великих зображень, не спричиняючи OutOfMemoryErrors, шляхом підстановки зображення при зменшенні масштабу та завантаження плит високої роздільної здатності при збільшенні. Тепер він підтримує використання в руці ViewPager, обертання вручну або використання інформації EXIF ​​(90 ° зупинки), переосмислити вибрані події дотику, використовуючи OnClickListenerабо свій, GestureDetectorабо OnTouchListenerпідкласинг для додавання накладок, панорамування під час масштабування та імпульс.

Він не призначений як загальна заміна використання, ImageViewтому не розширює його та не підтримує відображення зображень із ресурсів, лише активів та зовнішніх файлів. Для цього потрібно SDK 10.

Джерело знаходиться на GitHub, і є зразок, який ілюструє використання в ViewPager.

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


1

Ви можете спробувати використовувати 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 = збільшення (вірно); ZoomOut = збільшення (помилкове);


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

і папка, що малюється, повинна мати файл зображення bticn. чудово працює :)


0

Щось подібне нижче це зробить.

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

Для перегляду повної програми дивіться тут: Програма для збільшення зображення в android

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.