Посмотреть пейджер + ImageView +Pinch Zoom + Поворот

Я хочу реализовать Pinch Zoom для ImageView, с помощью View Pager, похожего на галерею Android по умолчанию. Я нашел несколько источников через GitHub, но масштабирование и скольжение работают только для первого изображения.

Что я пробовал:

1.) TouchImageView

2.) PhotoView

3.) Галерея Android Touch

Все вышеперечисленные ссылки отлично работают для просмотра одного изображения. Но когда дело доходит до изображений в пейджере View, они имеют некоторые глюки и прекрасно работают только для первого изображения в пейджере View. Когда мы переходим к 3-му 4-му изображению в пейджере, функция перетаскивания не работает должным образом, если изображение увеличено.

Пожалуйста, если кто-нибудь знает какую-либо хорошую библиотеку для этого, предоставьте мне ссылку на них.

7 ответов

Решение

РЕДАКТИРОВАТЬ 2: Пример кода был передан в главную ветку TouchImageView. Вот ссылка на пример деятельности и ссылка на ExtendedViewPager.


РЕДАКТИРОВАТЬ: добавлен код, адаптирующий пример ссылки на TouchImageView. Примечание: вам понадобится последний код, который в данный момент находится в ветке dev. В будущем это будет включено в v1.2.0. Вы знаете, что имеете последний код, если TouchImageView переопределяет canScrollHorizontally.

Шаг 1: Расширьте ViewPager и переопределите canScroll для вызова canScrollHorizontallyFroyo.

public class ExtendedViewPager extends ViewPager {

public ExtendedViewPager(Context context) {
    super(context);
}

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

@Override
protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {
    if (v instanceof TouchImageView) {
        return ((TouchImageView) v).canScrollHorizontallyFroyo(-dx);
    } else {
        return super.canScroll(v, checkV, dx, x, y);
    }
}

}

Шаг 2. Измените TouchImageView, добавив canScrollHorizontallyFroyo:

public boolean canScrollHorizontallyFroyo(int direction) {
    return canScrollHorizontally(direction);
}

Шаг 3: Ваша деятельность

public class TouchImageViewActivity extends Activity {

@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        ExtendedViewPager mViewPager = (ExtendedViewPager) findViewById(R.id.view_pager);
        setContentView(mViewPager);
        mViewPager.setAdapter(new TouchImageAdapter());
    }

    static class TouchImageAdapter extends PagerAdapter {

            private static int[] images = { R.drawable.img1, R.drawable.img2, R.drawable.img3 };

            @Override
            public int getCount() {
                    return images.length;
            }

            @Override
            public View instantiateItem(ViewGroup container, int position) {
                    TouchImageView img = new TouchImageView(container.getContext());
                    img.setImageResource(images[position]);
                    container.addView(img, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
                    return img;
            }

            @Override
            public void destroyItem(ViewGroup container, int position, Object object) {
                    container.removeView((View) object);
            }

            @Override
            public boolean isViewFromObject(View view, Object object) {
                    return view == object;
            }

    }
}

Шаг 4: main.xml

<com.example.touch.ExtendedViewPager 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/view_pager"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

TouchImageView на самом деле мой проект. В настоящее время у меня есть исправление в ветке dev для интеграции с ViewPagers, которое будет передано мастеру в следующем выпуске. К сожалению, это исправление применимо только для API 14 и выше, так как сотовые и более ранние версии не вызывают canScrollHorizontally, Если вам нужно поддерживать более старые API, вам нужно будет обойти это в вашем ViewPager. Вот пример.

Я нашел симпатичное решение с библиотекой ImageViewZoom. Чтобы прокрутить увеличенное изображение в ViewPager, я создал собственный ViewPager:

public class ExtendedViewPager extends ViewPager {

    public ExtendedViewPager(Context context) {
        super(context);
    }

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

    @Override
    protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {
        if (v instanceof ImageViewTouch) {
            return ((ImageViewTouch) v).canScroll(dx);
        } else {
            return super.canScroll(v, checkV, dx, x, y);
        }
    }
}

Подробнее https://gist.github.com/atermenji/3781644

После нескольких часов тестирования вышеупомянутых решений я наконец-то нашел потрясающую библиотеку View View с масштабированием субсэмплинга, которая работает даже со стандартным ViewPager из пакета поддержки Android.

Мое решение с использованием библиотеки ImageViewZoom основано на этом пользовательском ViewPager:

public class ImageViewTouchViewPager extends ViewPager {

    public ImageViewTouchViewPager(Context context) {
        super(context);
    }

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

    @Override
    protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {
        if (v instanceof ImageViewTouch) {
            ImageViewTouch imageViewTouch = (ImageViewTouch)v;
            if (imageViewTouch.getScale() == imageViewTouch.getMinScale()) {
                return super.canScroll(v, checkV, dx, x, y);
            }
            return imageViewTouchCanScroll(imageViewTouch, dx);
        } else {
            return super.canScroll(v, checkV, dx, x, y);
        }
    }


    /**
     * Determines whether the ImageViewTouch can be scrolled.
     *
     * @param direction - positive direction value means scroll from right to left,
     *                  negative value means scroll from left to right
     * @return true if there is some more place to scroll, false - otherwise.
     */
    private boolean imageViewTouchCanScroll(ImageViewTouch v, int direction){
        RectF bitmapRect = v.getBitmapRect();
        Rect imageViewRect = new Rect();
        getGlobalVisibleRect(imageViewRect);

        if (null == bitmapRect) {
            return false;
        }

        if (direction < 0) {
            return Math.abs(bitmapRect.right - imageViewRect.right) > 1.0f;
        }else {
            return Math.abs(bitmapRect.left - imageViewRect.left) > 1.0f;
        }

    }
}

Для тех, кто изо всех сил пытается отключить окно просмотра, когда изображение зажато для увеличения, и включить, когда изображение находится в исходном состоянии. Я просто внес некоторые изменения, как ответил Майк.

import android.content.Context
import android.util.AttributeSet
import android.util.Log
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import androidx.viewpager.widget.ViewPager


class DCExtendedViewPager : ViewPager {


    private val TAG = DCExtendedViewPager::class.java.simpleName

    private var onImageState: OnImageState? = null

    private var touchImageViewCustom: DCTouchImageViewLatest? = null


    var isScroll: Boolean = true

    interface OnImageState {
        fun checkImageState(isImageInOriginalState: Boolean)
    }


    constructor(context: Context) : super(context)

    constructor(context: Context, attrs: AttributeSet) : super(context, attrs)


    override fun canScroll(view: View, checkV: Boolean, dx: Int, x: Int, y: Int): Boolean {
        return if (view is DCTouchImageViewLatest) {
            //   touchImageView=view
            // canScrollHorizontally is not supported for Api < 14. To get around this issue,
            // ViewPager is extended and canScrollHorizontallyFroyo, a wrapper around
            // canScrollHorizontally supporting Api >= 8, is called.
            Log.e("ExtendedViewPager", "canScroll zoomedRect" + view.zoomedRect)

            view.canScrollHorizontallyFroyo(-dx)

        } else {
            super.canScroll(view, checkV, dx, x, y)
        }
    }

    override fun onTouchEvent(event: MotionEvent): Boolean {
        Log.e(TAG, "onTouchEventenable" + isScroll)
        return if (isScroll) {
            super.onTouchEvent(event)
        } else false

    }

    override fun onInterceptTouchEvent(event: MotionEvent): Boolean {

        Log.e(TAG, "onInterceptTouchEvent")

        Log.e(TAG, "currenrLayoutView called")
        val currenrLayoutView = getCurrentParentView()
        getTouchImageViewInstance(currenrLayoutView!!)

        return if (isScroll) {
            super.onInterceptTouchEvent(event)
        } else false

    }


    fun isViewPagerScrollValid(): Boolean {

        Log.e(TAG, "getFocusedChild()" + focusedChild)


        val currenrLayoutView = getCurrentParentView()


        var zoomRect = getTouchImageViewInstance(currenrLayoutView!!)?.zoomedRect
        var orgzoomRect = getTouchImageViewInstance(currenrLayoutView)?.originalRectF


        Log.e(TAG, "onInterceptTouchEvent zoomRect" + zoomRect)
        Log.e(TAG, "onInterceptTouchEvent orgzoomRect" + orgzoomRect)
        Log.e(TAG, "onInterceptTouchEvent onImageState" + onImageState)
        var scrollEnable = (zoomRect == orgzoomRect)


        // postLater(getTouchImageViewInstance(currenrLayoutView!!)!!)

        onImageState?.checkImageState(scrollEnable)
        Log.e(TAG, "onInterceptTouchEvent" + scrollEnable)


        return scrollEnable

    }


    fun setImageStateListner(onImageState: OnImageState) {
        this.onImageState = onImageState
    }


    fun getTouchImageViewInstance(accessingView: View): DCTouchImageViewLatest? {


        if (touchImageViewCustom == null) {

            try {
                for (index in 0 until (accessingView as ViewGroup).childCount) {

                    var nextChild = accessingView.getChildAt(index)

                    Log.e(TAG, "nextChild" + nextChild)

                    if (nextChild is ViewGroup) {
                        getTouchImageViewInstance(nextChild)
                    } else if (nextChild is View) {
                        if (nextChild is DCTouchImageViewLatest) {
                            touchImageViewCustom = nextChild
                            setListner()
                            break
                        }
                    }
                }

            } catch (ex: Exception) {
                ex.printStackTrace()
            }


        }


        Log.e(TAG, "getTouchImageViewInstance" + touchImageViewCustom)

        return touchImageViewCustom
    }

    private fun setListner() {

        touchImageViewCustom?.setOnDCTouchImageViewLatestListener(object : DCTouchImageViewLatest.OnDCTouchImageViewLatestListener {
            override fun onMove() {
                Log.e(TAG, "onMove Called")
                isScroll = isViewPagerScrollValid()
            }

        })

    }


    //Call this method from onPageSelected of viewpager
    fun viewPageChanged() {
        Log.e(TAG, "viewPageChanged called")
        touchImageViewCustom = null
    }


    fun getCurrentParentView(): View? {
        try {
            Log.e(TAG, "getCurrentView called")
            val currentItem = currentItem
            for (i in 0 until childCount) {
                val child = getChildAt(i)
                val layoutParams = child.layoutParams as ViewPager.LayoutParams

                val f = layoutParams.javaClass.getDeclaredField("position") //NoSuchFieldException
                f.isAccessible = true
                val position = f.get(layoutParams) as Int //IllegalAccessException

                Log.e(TAG, "currentItem" + currentItem)

                if (!layoutParams.isDecor && currentItem == position) {
                    Log.e(TAG, "getCurrentView" + child)
                    return child
                }
            }
        } catch (e: NoSuchFieldException) {
            Log.e(TAG, e.toString())
        } catch (e: IllegalArgumentException) {
            Log.e(TAG, e.toString())
        } catch (e: IllegalAccessException) {
            Log.e(TAG, e.toString())
        }

        return null
    }


}

В классе TouchImageView вызовите getOriginalRectF() из setImageBitmap, setImageDrawable и setImageURI.

 public RectF getOriginalRectF(){

        Log.e(TAG,"getOriginalRectF called viewWidth"+viewWidth);
        Log.e(TAG,"getOriginalRectF called viewHeight"+viewHeight);

        if(originalRectF==null && viewHeight>0 && viewWidth>0){
            if (mScaleType == ScaleType.FIT_XY) {
                throw new UnsupportedOperationException("getZoomedRect() not supported with FIT_XY");
            }
            PointF topLeft = transformCoordTouchToBitmap(0, 0, true);
            PointF bottomRight = transformCoordTouchToBitmap(viewWidth, viewHeight, true);

            float w = getDrawableWidth(getDrawable());
            float h = getDrawableHeight(getDrawable());


            Log.e(TAG,"getOriginalRectF height"+h);
            Log.e(TAG,"getOriginalRectF width"+w);

            Log.e("getOriginalRectF","getZoomedRect topLeft"+topLeft.x +"-"+topLeft.y);
            Log.e("getOriginalRectF","getZoomedRect bottomRight"+bottomRight.x +"-"+bottomRight.y);


            originalRectF=new  RectF(topLeft.x / w, topLeft.y / h, bottomRight.x / w, bottomRight.y / h);


        }


        return originalRectF;

    }

Я исправил предыдущее решение. Вы можете прокрутить страницу, когда ImageViewTouch находится в режиме масштабирования.

public class ImageViewTouchViewPager extends ViewPager {

public ImageViewTouchViewPager(Context context) {
    super(context);
}

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

@Override
protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {
    if (v instanceof ImageViewTouch) {
        ImageViewTouch imageViewTouch = (ImageViewTouch)v;
        return imageViewTouchCanScroll(imageViewTouch, dx);
    } else {
        return super.canScroll(v, checkV, dx, x, y);
    }
}


/**
 * Determines whether the ImageViewTouch can be scrolled.
 *
 * @param direction - positive direction value means scroll from right to left,
 *                  negative value means scroll from left to right
 * @return true if there is some more place to scroll, false - otherwise.
 */
private boolean imageViewTouchCanScroll(ImageViewTouch imageViewTouch, int direction){
    int widthScreen = getWidthScreen();

    RectF bitmapRect = imageViewTouch.getBitmapRect();
    Rect imageViewRect = new Rect();
    getGlobalVisibleRect(imageViewRect);

    int widthBitmapViewTouch = (int)bitmapRect.width();

    if (null == bitmapRect) {
        return false;
    }

    if(widthBitmapViewTouch < widthScreen){
        return false;
    }

    if (direction < 0) {
        return Math.abs(bitmapRect.right - imageViewRect.right) > 1.0f;
    }else {
        return Math.abs(bitmapRect.left - imageViewRect.left) > 1.0f;
    }

}

private int getWidthScreen(){
    WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
    Display display = wm.getDefaultDisplay();

    Point size = new Point();
    display.getSize(size);
    return size.x;
}

}

Ни одно из вышеперечисленных решений не сработало для меня. Это сработало для меня, когда я использовал следующий ImageView:

      import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewTreeObserver;
import android.view.animation.DecelerateInterpolator;
import android.widget.ImageView;

@SuppressLint("AppCompatCustomView")
public class TouchImageView extends ImageView implements ViewTreeObserver.OnGlobalLayoutListener,View.OnTouchListener {
    private final static int SINGLE_TOUCH = 1; //Single point
    private final static int DOUBLE_TOUCH = 2; //Double finger

    //Multi-finger touch mode, single finger, double finger
    private int mode;

    //Distance between two finger touch points
    private float oldDist;
    private float newDist;

    /**
     * Maximum zoom level
     */
    private static final float MAX_SCALE = 5f;
    /**
     * Double-click the zoom level
     */
    private  float mDoubleClickScale = 2;


    /**
     * Scales when initialization, if the picture is wide or higher than the screen, this value will be less than 0
     */
    private float initScale = 1.0f;
    private boolean once = true;
    private RectF rectF;

    /**
     * Double-click detection
     */
    private GestureDetector mGestureDetector;
    private int x = 0;
    private int y = 0;

    private Point mPoint = new Point();

    private final Matrix matrix = new Matrix();
    private Matrix oldMatrix = new Matrix();

    private ValueAnimator animator;

    public TouchImageView(Context context) {
        this(context, null);
    }

    public TouchImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        super.setScaleType(ScaleType.MATRIX);
        setOnTouchListener(this);
        /**
         * Double click to implement the picture to zoom
         */
        mGestureDetector = new GestureDetector(context,
                new GestureDetector.SimpleOnGestureListener() {
                    @Override
                    public boolean onDoubleTap(MotionEvent e) {
                        changeViewSize(e);
                        return true;
                    }
                });
    }

    @Override
    public boolean onTouch(View view, MotionEvent event) {
        rectF = getMatrixRectF(); //Get image boundaries
        if (mGestureDetector.onTouchEvent(event))
            return true;

        switch (event.getAction() & event.getActionMasked()) {
            case MotionEvent.ACTION_DOWN:
                //If the boundary of the picture is overstelled, then intercept the event, not letting ViewPager processing
                if (rectF.width() > getWidth() || rectF.height() > getHeight()) {
                    getParent().requestDisallowInterceptTouchEvent(true);
                }
                mode = SINGLE_TOUCH;

                x = (int) event.getRawX();
                y = (int) event.getRawY();
                break;
            case MotionEvent.ACTION_MOVE:
                if (mode >= DOUBLE_TOUCH) //Double finger zoom
                {
                    getParent().requestDisallowInterceptTouchEvent(true);
                    newDist = calculateDist(event); //Calculate distance
                    Point point = getMiPoint(event); //Get the midpoint coordinates between the two-hand fingers
                    if (newDist > oldDist + 1) //Pixabay (add one to prevent jitter)
                    {
                        changeViewSize(oldDist, newDist, point); //Enlarge reduction according to distance
                        oldDist = newDist;
                    }
                    if (oldDist > newDist + 1) //Narrow
                    {
                        changeViewSize(oldDist, newDist, point);
                        oldDist = newDist;
                    }
                }
                if (mode == SINGLE_TOUCH) //Drag and drop
                {
                    float dx = event.getRawX() - x;
                    float dy = event.getRawY() - y;

                    //If the boundary of the picture in the movement exceeds the screen, then intercept the event, do not let ViewPager processing
                    if (rectF.width() > getWidth() || rectF.height() > getHeight()) {
                        getParent().requestDisallowInterceptTouchEvent(true);
                    }
                    //If you move the picture to the right, don't intercept the event, let the ViewPager process
                    if (rectF.left >= 0 && dx > 0)
                        getParent().requestDisallowInterceptTouchEvent(false);

                    //If you move to the left, don't intercept the event, let ViewPager processing
                    if (rectF.right <= getWidth() && dx < 0)
                        getParent().requestDisallowInterceptTouchEvent(false);

                    if (getDrawable() != null) {
                        //If the image width or height does not exceed the screen, then it is forbidden to slide around or down.
                        if (rectF.width() <= getWidth())
                            dx = 0;
                        if (rectF.height() < getHeight())
                            dy = 0;

                        //If the picture moves down to the end, don't let it continue to move
                        if (rectF.top >= 0 && dy > 0)
                            dy = 0;
                        //If the picture moves up to the end, don't let it continue to move
                        if (rectF.bottom <= getHeight() && dy < 0)
                            dy = 0;

                        //When the movement distance is greater than 1, it moves because Action_Move is relatively sensitive.
                        //  The finger can only detect the jitter of the finger and let the picture move.
                        if (Math.abs(dx) > 1 || Math.abs(dy) > 1)
                            matrix.postTranslate(dx, dy);
                        setImageMatrix(matrix);
                    }
                }
                x = (int) event.getRawX();
                y = (int) event.getRawY();
                break;
            case MotionEvent.ACTION_POINTER_DOWN:
                mode += 1;
                oldDist = calculateDist(event);
                Log.e("q", "" + "a");

                Log.e(":::", "" + event.getPointerCount() + "   " + event.getActionIndex() + "   " + event.findPointerIndex(0));
                break;
            case MotionEvent.ACTION_POINTER_UP:
                mode -= 1;
                break;
            case MotionEvent.ACTION_UP:
                backToPosition();
                mode = 0;
                break;
            //In Action_Move, the event is intercepted, sometimes Action_up can't trigger, so add Action_Cancel
            case MotionEvent.ACTION_CANCEL:
                backToPosition();
                mode = 0;
                break;
            default:
                break;
        }
        return true;
    }

    /**
     * Calculate the distance between two finger touch points
     */
    private float calculateDist(MotionEvent event) {

        float x = event.getX(0) - event.getX(1);
        float y = event.getY(0) - event.getY(1);
        return (float) Math.sqrt(x * x + y * y);

    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        getViewTreeObserver().addOnGlobalLayoutListener(this);
    }

    /**
     * If it is separated from the screen boundary, then the image boundary is combined with the screen boundary.
     * If the finger moves quickly, the picture will have a blank distance after the picture is stopped, and then the judgment can no longer move,
     * However, it has appeared before the next judgment can continue to move.
     * So you need to reset
     */
    private void backToPosition() {
        if (rectF.left >= 0) { //Image Left boundary and screen from the screen
            matrix.postTranslate(-rectF.left, 0);
            setImageMatrix(matrix);
        }
        if (rectF.right <= getWidth()) { //Image Right Boundary and Screen Distance
            matrix.postTranslate(getWidth() - rectF.right, 0);
            setImageMatrix(matrix);
        }
        if (rectF.top >= 0) { //Image on the image and the screen from the screen
            matrix.postTranslate(0, -rectF.top);
            setImageMatrix(matrix);
        }
        if (rectF.bottom <= getHeight()) { //Image of the image and the screen
            matrix.postTranslate(0, getHeight() - rectF.bottom);
            setImageMatrix(matrix);
        }
    }


    /**
     * Get the zoom in the zoom of double finger zoom
     *
     * @return
     */
    private Point getMiPoint(MotionEvent event) {

        float x = event.getX(0) + event.getX(1);
        float y = event.getY(0) + event.getY(1);

        mPoint.set((int) x / 2, (int) y / 2);
        return mPoint;
    }

    /**
     * Double finger zoom picture
     */
    private void changeViewSize(float oldDist, float newDist, Point mPoint) {
        float scale = newDist / oldDist; //scaling ratio

        matrix.postScale(scale, scale, mPoint.x, mPoint.y);
        checkBorderAndCenterWhenScale();
        setImageMatrix(matrix);

        //Prevent reduction is less than the initial picture size, need to reset
        reSetMatrix();
        //If the zoom has been larger than the target multiple, stop, because it is possible to be exceeded, then directly zoom to the target size
        if (getMatrixValueX() >= MAX_SCALE)
        {
            matrix.postScale(MAX_SCALE/getMatrixValueX(), MAX_SCALE/getMatrixValueX(), x, y);
            checkBorderAndCenterWhenScale();
            setImageMatrix(matrix);
            return;
        }
    }

    /**
     * Double click to zoom pictures
     */
    private void changeViewSize(MotionEvent e) {

        //Get double-click coordinates
        final float x = e.getX();
        final float y = e.getY();

        //If you are still zooming, you will return directly.
        if (animator != null && animator.isRunning())
            return;

        //Judgment is a state in which it is amplified or reduced
        if (!isZoomChanged()) {
            animator = ValueAnimator.ofFloat(1.0f, 2.0f);
        } else {
            animator = ValueAnimator.ofFloat(1.0f, 0.0f);
        }
        animator.setTarget(this);
        animator.setDuration(500);
        animator.setInterpolator(new DecelerateInterpolator());
        animator.start();
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {

                Float value = (Float) animator.getAnimatedValue();
                matrix.postScale(value, value, x, y);
                checkBorderAndCenterWhenScale();
                setImageMatrix(matrix);

                /**
                 * Control reduction range
                 * If it is already less than the initial size, then restore to the initial size, then stop
                 */
                if (checkRestScale()) {
                    matrix.set(oldMatrix);
                    setImageMatrix(matrix);
                    return;
                }
                /**
                 * Control the range of amplification
                 * If the magnification of the target is already larger than the target, it is directly in the target magnification.
                 * Then stop
                 */
                if (getMatrixValueX() >= mDoubleClickScale)
                {
                    matrix.postScale(mDoubleClickScale/getMatrixValueX(), mDoubleClickScale/getMatrixValueX(), x, y);
                    checkBorderAndCenterWhenScale();
                    setImageMatrix(matrix);
                    return;
                }
            }
        });
    }

    /**
     * Judging whether the zoom level is changed
     *
     * @return  TRUE expressed the non-initial value, FALSE indicates the initial value.
     */
    private boolean isZoomChanged() {
        float[] values = new float[9];
        getImageMatrix().getValues(values);
        //Get the current X-axis scale level
        float scale = values[Matrix.MSCALE_X];
        //Get the X-axis scaling level of the template, both
        oldMatrix.getValues(values);
        return scale != values[Matrix.MSCALE_X];
    }

    /**
     * Reset Matrix
     */
    private void reSetMatrix() {
        if (checkRestScale()) {
            matrix.set(oldMatrix);
            setImageMatrix(matrix);
            return;
        }
    }

    /**
     * Setup double-click a large multiple
     */
    private void setDoubleClickScale(RectF rectF)
    {
        if(rectF.height()<getHeight()-100)
        {
            mDoubleClickScale=getHeight()/rectF.height();
        }
        else
            mDoubleClickScale=2f;
    }

    /**
     * Judging whether it needs to be reset
     *
     * @return  When the current zoom level is less than the template zoom level, reset
     */
    private boolean checkRestScale() {
        // TODO Auto-generated method stub
        float[] values = new float[9];
        getImageMatrix().getValues(values);
        //Get the current X-axis scale level
        float scale = values[Matrix.MSCALE_X];
        //Get the X-axis scaling level of the template, both
        oldMatrix.getValues(values);
        return scale < values[Matrix.MSCALE_X];
    }

    private float getMatrixValueX()
    {
        // TODO Auto-generated method stub
        float[] values = new float[9];
        getImageMatrix().getValues(values);
        //Get the current X-axis scale level
        float scale = values[Matrix.MSCALE_X];
        //Get the X-axis scaling level of the template, both
        oldMatrix.getValues(values);
        return scale / values[Matrix.MSCALE_X];
    }
    /**
     * When zooming, perform image display scope control
     */
    private void checkBorderAndCenterWhenScale()
    {

        RectF rect = getMatrixRectF();
        float deltaX = 0;
        float deltaY = 0;

        int width = getWidth();
        int height = getHeight();

        //  Control range if wide or higher than the screen
        if (rect.width() >= width)
        {
            if (rect.left > 0)
            {
                deltaX = -rect.left;
            }
            if (rect.right < width)
            {
                deltaX = width - rect.right;
            }
        }
        if (rect.height() >= height)
        {
            if (rect.top > 0)
            {
                deltaY = -rect.top;
            }
            if (rect.bottom < height)
            {
                deltaY = height - rect.bottom;
            }
        }
        //  If the width or higher is less than the screen, let it hit
        if (rect.width() < width)
        {
            deltaX = width * 0.5f - rect.right + 0.5f * rect.width();
        }
        if (rect.height() < height)
        {
            deltaY = height * 0.5f - rect.bottom + 0.5f * rect.height();
        }
        Log.e("TAG", "deltaX = " + deltaX + " , deltaY = " + deltaY);

        matrix.postTranslate(deltaX, deltaY);
        setImageMatrix(matrix);
    }
    /**
     * Get the range of images according to the Matrix of the current picture
     *
     * @return
     */
    private RectF getMatrixRectF()
    {
        RectF rect = new RectF();
        Drawable d = getDrawable();
        if (null != d)
        {
            rect.set(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
            matrix.mapRect(rect); //If this is not this, the output of the following Log will be the same as the previous sentence.
        }
        Log.e("aaaa",""+rect.bottom+"  "+rect.left+"   "+rect.right+"  "+rect.top);
        return rect;
    }

    @Override
    public void onGlobalLayout() {
        if (once)
        {
            Drawable d = getDrawable();
            if (d == null)
                return;
            Log.e("TAG", d.getIntrinsicWidth() + " , " + d.getIntrinsicHeight());
            int width = getWidth();
            int height = getHeight();
            //  Get the width and high of the picture
            int dw = d.getIntrinsicWidth();
            int dh = d.getIntrinsicHeight();
            float scale = 1.0f;
            // If the image is wide or higher than the screen, zoom to the width or high of the screen.
            if (dw > width && dh <= height)
            {
                scale = width * 1.0f / dw;
            }
            if (dh > height && dw <= width)
            {
                scale = height * 1.0f / dh;
            }
            //  If the width and high are greater than the screen, it will make it adapt to the screen size according to the proportion.
            if (dw > width && dh > height)
            {
                scale = Math.min(width * 1.0f / dw, height * 1.0f / dh);
            }
            initScale = scale;

            Log.e("TAG", "initScale = " + initScale);
            matrix.postTranslate((width - dw) / 2, (height - dh) / 2);
            matrix.postScale(scale, scale, getWidth() / 2,
                    getHeight() / 2);
            //  Image Move to the screen center
            setImageMatrix(matrix);

            oldMatrix.set(getImageMatrix());
            once = false;

            RectF rectF=getMatrixRectF();
            setDoubleClickScale(rectF);

        }
    }
}

Кроме того, я использовал приведенный ниже ExtendedViewPager:

      import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import androidx.viewpager.widget.ViewPager;

public class ExtendedViewPager extends ViewPager {

    public ExtendedViewPager(Context context) {
        super(context);
    }

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

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        try {
            return super.onTouchEvent(ev);
        } catch (IllegalArgumentException ex) {
            ex.printStackTrace();
        }
        return false;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        try {
            return super.onInterceptTouchEvent(ev);
        } catch (IllegalArgumentException ex) {
            ex.printStackTrace();
        }
        return false;
    }


}
Другие вопросы по тегам