Linked Questions

Popular Questions

I'm using this code as custom Zoom Image, it works great if alone but alongside a viewpager2 it doesn't work with the pager's child onTouch listener. In sharedConstructing I've set super.setClickable(true); and it blocks the pager's child touch events and removing it it's the opposite: works for the pager's child but not the zoom image onTouch listener. Since the pager's child has to do some stuff to change page basend on where you click on it (like left part it changes to previous item, right to the next item) I need both touches to work together. The pager's child uses only ACTION_DOWN and ACTION_UP to get X/Y so I need to make them work together keeping the ZoomImageView alone since is part of a library I did for myself. Can someone help me? Thanks!

public class ZoomImageView extends androidx.appcompat.widget.AppCompatImageView {

// We can be in one of these 3 states
static final int NONE = 0;
static final int DRAG = 1;
static final int ZOOM = 2;
static final int CLICK = 3;
private final int CLICK_THRESHOLD = 20;
public int mode = NONE;
protected float origWidth, origHeight;
Matrix matrix;
// Remember some things for zooming
PointF last = new PointF();
PointF start = new PointF();
float minScale = 1f;
float maxScale = 5f;
float[] m;
int viewWidth, viewHeight;
float saveScale = 1f;
int oldMeasuredWidth, oldMeasuredHeight;

ScaleGestureDetector mScaleDetector;
Context context;

public ZoomImageView(Context context) {
    super(context);
    sharedConstructing(context);
}

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

private void stopInterceptEvent() {
    if (getParent() != null) getParent().requestDisallowInterceptTouchEvent(true);
}

private void startInterceptEvent() {
    if (getParent() != null) getParent().requestDisallowInterceptTouchEvent(false);
}

private void sharedConstructing(Context context) {
    super.setClickable(true);
    this.context = context;
    mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
    matrix = new Matrix();
    m = new float[9];
    setImageMatrix(matrix);
    setScaleType(ScaleType.MATRIX);
    setOnTouchListener((v, event) -> {
        mScaleDetector.onTouchEvent(event);
        PointF curr = new PointF(event.getX(), event.getY());
        switch (event.getAction() & event.getActionMasked()) {
            case MotionEvent.ACTION_DOWN:
                last.set(curr);
                start.set(last);
                mode = DRAG;
                stopInterceptEvent();
                break;

            case MotionEvent.ACTION_MOVE:
                stopInterceptEvent();
                if (mode == DRAG) {
                    float deltaX = curr.x - last.x;
                    float deltaY = curr.y - last.y;
                    float fixTransX = getFixDragTrans(deltaX, viewWidth,
                            origWidth * saveScale);
                    float fixTransY = getFixDragTrans(deltaY, viewHeight,
                            origHeight * saveScale);
                    matrix.postTranslate(fixTransX, fixTransY);
                    fixTrans();
                    last.set(curr.x, curr.y);
                    if (mScaleDetector.getScaleFactor() == saveScale)
                        startInterceptEvent();
                    else
                        stopInterceptEvent();
                }
                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);
                startInterceptEvent();
                if (xDiff < CLICK_THRESHOLD && yDiff < CLICK_THRESHOLD)
                    performClick();
                break;
            case MotionEvent.ACTION_POINTER_UP:
                mode = NONE;
                callOnClick();
                break;
        }

        setImageMatrix(matrix);
        invalidate();
        return false; // indicate event was handled
    });
}

void fixTrans() {
    matrix.getValues(m);
    float transX = m[Matrix.MTRANS_X];
    float transY = m[Matrix.MTRANS_Y];

    float fixTransX = getFixTrans(transX, viewWidth, origWidth * saveScale);
    float fixTransY = getFixTrans(transY, viewHeight, origHeight
            * saveScale);

    if (fixTransX != 0 || fixTransY != 0)
        matrix.postTranslate(fixTransX, fixTransY);
}

float getFixTrans(float trans, float viewSize, float contentSize) {
    float minTrans, maxTrans;

    if (contentSize <= viewSize) {
        minTrans = 0;
        maxTrans = viewSize - contentSize;
    } else {
        minTrans = viewSize - contentSize;
        maxTrans = 0;
    }

    if (trans < minTrans)
        return -trans + minTrans;
    if (trans > maxTrans)
        return -trans + maxTrans;
    return 0;
}

float getFixDragTrans(float delta, float viewSize, float contentSize) {
    if (contentSize <= viewSize) {
        return 0;
    }
    return delta;
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    viewWidth = MeasureSpec.getSize(widthMeasureSpec);
    viewHeight = MeasureSpec.getSize(heightMeasureSpec);

    //
    // Rescales image on rotation
    //
    if (oldMeasuredHeight == viewWidth && oldMeasuredHeight == viewHeight
            || viewWidth == 0 || viewHeight == 0)
        return;
    oldMeasuredHeight = viewHeight;
    oldMeasuredWidth = viewWidth;

    if (saveScale == 1) {
        // Fit to screen.
        float scale;

        Drawable drawable = getDrawable();
        if (drawable == null || drawable.getIntrinsicWidth() == 0
                || drawable.getIntrinsicHeight() == 0)
            return;
        int bmWidth = drawable.getIntrinsicWidth();
        int bmHeight = drawable.getIntrinsicHeight();

        Log.d("bmSize", "bmWidth: " + bmWidth + " bmHeight : " + bmHeight);

        float scaleX = (float) viewWidth / (float) bmWidth;
        float scaleY = (float) viewHeight / (float) bmHeight;
        scale = Math.min(scaleX, scaleY);
        matrix.setScale(scale, scale);

        //Center the image
        float redundantYSpace = (float) viewHeight - (scale * (float) bmHeight);
        float redundantXSpace = (float) viewWidth - (scale * (float) bmWidth);
        redundantYSpace /= (float) 2;
        redundantXSpace /= (float) 2;

        matrix.postTranslate(redundantXSpace, redundantYSpace);

        origWidth = viewWidth - 2 * redundantXSpace;
        origHeight = viewHeight - 2 * redundantYSpace;
        setImageMatrix(matrix);
    }
    fixTrans();
}

private class ScaleListener extends
        ScaleGestureDetector.SimpleOnScaleGestureListener {
    @Override
    public boolean onScaleBegin(ScaleGestureDetector detector) {
        mode = ZOOM;
        return true;
    }

    @Override
    public boolean onScale(ScaleGestureDetector detector) {
        float mScaleFactor = detector.getScaleFactor();
        float origScale = saveScale;
        saveScale *= mScaleFactor;
        if (saveScale > maxScale) {
            saveScale = maxScale;
            mScaleFactor = maxScale / origScale;
        } else if (saveScale < minScale) {
            saveScale = minScale;
            mScaleFactor = minScale / origScale;
        }

        if (origWidth * saveScale <= viewWidth
                || origHeight * saveScale <= viewHeight)
            matrix.postScale(mScaleFactor, mScaleFactor, viewWidth / 2,
                    viewHeight / 2);
        else
            matrix.postScale(mScaleFactor, mScaleFactor,
                    detector.getFocusX(), detector.getFocusY());

        fixTrans();
        return true;
    }
}

}

Related Questions