Как я могу получить функцию масштабирования для изображений?

204

Есть ли общий способ показать большое изображение и позволить пользователю увеличивать и уменьшать масштаб и панорамировать изображение?

До сих пор я нашел два способа:

  1. перезапись ImageView, которая кажется слишком большой для такой распространенной проблемы.
  2. используя веб-просмотр, но с меньшим контролем общего макета и т. д.
Януш
источник
Существует ZOOM CONTROL (виджет), и вы можете прослушивать событие OnTouch для обработки панорамирования.
Тобриен
1
Подобный вопрос stackoverflow.com/questions/2537396/… , имеет ссылку на этот учебник anddev.org/… . Вы можете найти это полезным для панорамирования вашего iamge. Я не читал это подробно, но это также может дать вам некоторые идеи о том, как сделать функцию масштабирования.
Стив Хейли
Кто-нибудь пытался сохранить изображение при масштабировании? Я хочу, чтобы сохраненное изображение находилось в состоянии по умолчанию, а не в увеличенном состоянии. Пожалуйста, смотрите мой вопрос: stackoverflow.com/questions/24730793/… Спасибо
Blaze Tama

Ответы:

208

ОБНОВИТЬ

Я только что дал TouchImageView новое обновление. Теперь он включает Double Tap Zoom и Fling в дополнение к панорамированию и Pinch Zoom. Код ниже очень устарел. Вы можете проверить проект 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
@ Майк, я пробовал этот код, но пользовательская галерея не работает. Есть ли хитрость, чтобы обойти эту проблему.
Умеш
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);
    }
}
Роберт Фосс
источник
Роберт Фосс, если добавить к этому граничного судьи, он может оказаться лучше. Спасибо вам за ваш код очень хорошо
pengwang
3
Это работает, но я не вижу смысла WrapMotionEventи EclairMotionEvent... в любом случае, +1.
Cipi
2
Мультитач для телефонов, которые его поддерживают. Обычное прикосновение для Android <2.0
Роберт Фосс,
Хороший пример, он работает нормально, но я не понял, что такое Viewer, если (Viewer.isDebug == true) {dumpEvent (event); }
Тофик Ахмад
2
Что это? >> se.robertfoss.ChanImageBrowser.Viewer
emeraldhieu
60

Я использовал WebView и загрузил изображение из памяти через

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

WebView обрабатывает все масштабирование и прокрутку панорамирования. Если вы используете wrap_content, веб-просмотр не будет больше, чем изображение, и белые области не отображаются. WebView лучше ImageView;)

Януш
источник
5
Я использую тот же подход. У меня есть большая карта метро, ​​которую я хочу, чтобы пользователь мог масштабировать и прокручивать. Однако я заметил, что если у вас довольно большое изображение (то есть 1000 или 3000 пикселей в ширину), изображение становится размытым после увеличения. Кажется, что coliris не может отобразить большое увеличенное изображение с очень высокой резкостью. Хотя исходное изображение не сжато и очень резкое. Поэтому я закончил разрезать одно большое изображение на более мелкие кусочки и соединить их снова через HTML. Таким образом изображение остается резким при увеличении. (Я на Nexus One, 2.1 обновлялся до, а теперь на 2.2)
Матиас Конрадт
@Mathias Lin: если по сети отправляется большое изображение, я слышал, что операторы сжимают большие изображения. подойдет ли вам этот вариант использования или вы загрузили изображение локально.
Самуил
@Sam Quest: загрузка его локально
Матиас Конрадт
4
гораздо лучше использовать встроенные в веб-кнопки кнопки масштабирования и поддержку масштабирования для увеличения / уменьшения, чем при написании совершенно нового алгоритма, который может не работать на разных телефонах и в будущих выпусках платформы Android
sami
2
это решение может быть применено только в том случае, если у вас есть изображение, лежащее на диске, или изображение достаточно маленькое, чтобы вы могли кодировать и передавать строковое значение в loadUrlWithData ().
Джеффри Блатман
7

В ответе на оригинальный вопрос Януша есть несколько способов достижения этого, каждый из которых различается по уровню сложности и был указан ниже. Использование веб-представления - это хорошо, но оно очень ограничено с точки зрения внешнего вида и управляемости. Если вы рисуете растровое изображение с холста, наиболее универсальные решения, которые были предложены, это MikeOrtiz, Robert Foss и / или то, что предложил Jacob Nordfalk. Есть отличный пример для включения android-multitouch-контроллера от PaulBourke , и он отлично подходит для поддержки мультитач и всех типов пользовательских представлений.

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

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

К сожалению, из-за моего макета, мне нужно было "wrap_content" для "layout_height". Когда я изменил его на это, изображение было обрезано внизу, и я не мог прокрутить или увеличить область обрезки. Поэтому я взглянул на Source для 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);
}

Здесь resolSize (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 за его оригинальный код, отличная работа.

digiphd
источник
Это исправление было включено в репозиторий Майка github?
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
}
zontar
источник
3

@ Роберт Фосс, @ Майк Ортис, большое спасибо за вашу работу. Я объединил твою работу и закончил занятия Роберта для Android> 2.0 с дополнительной работой Майка.

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

Роман Труба
источник
2

Попробуйте использовать ZoomViewдля масштабирования любой другой вид.

http://code.google.com/p/android-zoom-view/ это просто, бесплатно и интересно!

karooolek
источник
Этот репозиторий больше не поддерживается.
erginduran
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);
    }

}
Terence
источник
2

Это очень позднее дополнение к этой теме, но я работаю над изображением, которое поддерживает масштабирование и панорамирование и имеет несколько функций, которых я не нашел в других местах. Это началось как способ отображения очень больших изображений без указания OutOfMemoryErrors, путем подвыборки изображения при уменьшении и загрузки листов с более высоким разрешением при увеличении. Теперь он поддерживает использование в a 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 = zoom (true); ZoomOut = zoom (false);

новичек
источник
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);
        }
    });
}

и в папке drawable должен быть файл изображения 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

Анимеш Шривастав
источник