2

RelativeLayout でズームとパンを実行する関数を実装していますが、ほぼ完了です。ただし、レイアウト内にビューがあり、変換を適用すると、これらのビューのタッチが更新されず、追跡できなくなります。

変換を実行することで、ズームとパンに応じて機能するビューのタッチが必要です。

以下のコードを共有し、ヘルプをリクエストして、完成させます。

public class ZoomLayout extends RelativeLayout implements OnTouchListener, OnDoubleTapListener, OnGestureListener {

// ===================================================================================
// ==================================== ATRIBUTES ====================================
// ===================================================================================


private float currentScaleFactor = 1.0f;

private float previousScaleFactor = 1.0f;

private ScaleGestureDetector scaleGestureDetector;

private GestureDetector gestureDetector;

private float xPrevious;

private float yPrevious;

private float xActual;

private float yActual;

private float leftStage;

private float topStage;

private float xInitial;

private float yInitial;

private float maxScale = 5f;

private float minScale = 0.3f;

private int widthStage;

private int heightStage;

private boolean firstTimeOnEvent = true;

private boolean zoomEnable = true;

private boolean oneFingerMoveEnable = false;

private boolean twoFingersMoveEnable = true;

private boolean doubleTapZoomEnable = true;

private Matrix savedMatrix = null;

private boolean onScale = false;

private float diferenceFromScaleX;

private float diferenceFromScaleY;

private List<ZoomListener> listeners = new CopyOnWriteArrayList<ZoomListener>();

// ===================================================================================
// =================================== CONTRUCTORS ==================================
// ===================================================================================

public ZoomLayout(Context context)
{
    super(context);

    setWillNotDraw(false);

    savedMatrix = new Matrix();

    savedMatrix.reset();

    scaleGestureDetector = new ScaleGestureDetector(getContext(), new ZoomScale());

    gestureDetector = new GestureDetector(context, this);

    gestureDetector.setOnDoubleTapListener(this);


    this.setOnTouchListener(this);
}

public ZoomLayout(Context context, int width, int height)
{
    this(context);

    this.widthStage = width;
    this.heightStage = height;
}

// ===================================================================================
// ===================================== METHODS =====================================
// ===================================================================================

public void setZoomScale(float scale)
{
    currentScaleFactor = scale;
    previousScaleFactor = scale;

    savedMatrix.reset();

    xActual = 0;
    yActual = 0;
    xPrevious = 0;
    yPrevious = 0;

    float maxLeft = ((float) (widthStage * 0.5) - (float) (widthStage * currentScaleFactor * 0.5));
    float maxTop = ((float) (heightStage * 0.5) - (float) (heightStage * currentScaleFactor * 0.5));

    savedMatrix.postScale(currentScaleFactor, currentScaleFactor);
    savedMatrix.postTranslate(maxLeft, maxTop);

    invalidate();
    requestLayout();

    leftStage = 0;
    topStage = 0; 
}


public void addZoomListener(ZoomListener listener)
{
    listeners.add(listener);
}


public void removeZoomListener(ZoomListener listener)
{
    listeners.remove(listener);
}

// ===================================================================================
// ===================================== EVENTS =====================================
// ===================================================================================

@Override
public boolean onTouch(View v, MotionEvent event)
{
    if (zoomEnable)
    {
        switch (event.getAction() & MotionEvent.ACTION_MASK)
        {
            case MotionEvent.ACTION_DOWN:

                break;

            case MotionEvent.ACTION_POINTER_DOWN:

                firstTimeOnEvent = true;

                break;

            case MotionEvent.ACTION_UP:

                firstTimeOnEvent = true;

                break;

            case MotionEvent.ACTION_POINTER_UP:

                break;

            case MotionEvent.ACTION_CANCEL:

                firstTimeOnEvent = true;

                break;

            case MotionEvent.ACTION_MOVE:

                break;
        }

        scaleGestureDetector.onTouchEvent(event);

        gestureDetector.onTouchEvent(event);

    }
    else
    {
        return false;
    }

    for (int i = 0; i < listeners.size(); i++)
    {
        listeners.get(i).onTouch(v, event);
    }

    return true;
}

@Override
public boolean onInterceptTouchEvent(MotionEvent ev)
{
    onTouchEvent(ev);
    return super.onInterceptTouchEvent(ev);
}

@Override
public ViewParent invalidateChildInParent(int[] location, Rect dirty) {

    return super.invalidateChildInParent(location, dirty);
}


@Override
protected void onLayout(boolean changed, int l, int t, int r, int b)
{
    int count = getChildCount();
    for(int i=0;i<count;i++){
        View child = getChildAt(i);
        if(child.getVisibility()!=GONE){
            RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams)child.getLayoutParams();
            child.layout(
                (int)(params.leftMargin*currentScaleFactor),
                (int)(params.topMargin*currentScaleFactor),
                (int)((params.leftMargin + child.getMeasuredWidth())*currentScaleFactor ),
                (int)((params.topMargin + child.getMeasuredHeight())*currentScaleFactor)
                );
            child.setLayoutParams(params);

        }
    }
}

@Override
protected void dispatchDraw(Canvas canvas)
{
    canvas.setMatrix(savedMatrix);

    super.dispatchDraw(canvas);
}


private class ZoomScale extends ScaleGestureDetector.SimpleOnScaleGestureListener
{

    @Override
    public boolean onScaleBegin(ScaleGestureDetector detector)
    {
        onScale = true;


        for (int i = 0; i < listeners.size(); i++)
        {
            listeners.get(i).onScaleBegin(detector);
        }

        return super.onScaleBegin(detector);
    }


    @Override
    public void onScaleEnd(ScaleGestureDetector detector)
    {

        onScale = false;


        diferenceFromScaleX = detector.getFocusX() - xActual;
        diferenceFromScaleY = detector.getFocusY() - yActual;


        for (int i = 0; i < listeners.size(); i++)
        {
            listeners.get(i).onScaleEnd(detector);
        }

        super.onScaleEnd(detector);
    }


    @Override
    public boolean onScale(ScaleGestureDetector detector)
    {

        xPrevious = xActual;
        yPrevious = yActual;


        xActual = scaleGestureDetector.getFocusX();
        yActual = scaleGestureDetector.getFocusY();

        if (!firstTimeOnEvent)
        {

            currentScaleFactor = (currentScaleFactor * detector.getScaleFactor());


            currentScaleFactor = (Math.max(Math.min(currentScaleFactor, maxScale), minScale));


            float diferencaScale = (currentScaleFactor / previousScaleFactor);


            float x = xActual - xPrevious;


            float y = yActual - yPrevious;


            savedMatrix.postScale(diferencaScale, diferencaScale, xInitial - x, yInitial - y);

            savedMatrix.postTranslate(x, y);

            float[] values = new float[9];

            savedMatrix.getValues(values);

            float leftAux = (float) values[Matrix.MTRANS_X];
            float topAux = (float) values[Matrix.MTRANS_Y];


            float maxLeft = 0;
            float maxTop = 0;

            if (widthStage * currentScaleFactor >= 1280)
            {

                maxLeft = -((float) (widthStage * currentScaleFactor) - (float) 1280);

                if (leftAux < 0)
                {

                    if (leftAux < maxLeft)
                    {

                        maxLeft -= leftAux;
                    }
                    else
                    {

                        maxLeft = 0;
                    }
                }
                else
                {

                    maxLeft = -leftAux;
                }
            }
            else
            {

                maxLeft = ((float) (widthStage * 0.5) - (float) (widthStage * currentScaleFactor * 0.5));

                maxLeft -= leftAux;
            }

            if (heightStage * currentScaleFactor >= 752)
            {

                maxTop = -((float) (heightStage * currentScaleFactor) - (float) 752);

                if (topAux < 0)
                {

                    if (topAux < maxTop)
                    {

                        maxTop -= topAux;
                    }
                    else
                    {

                        maxTop = 0;
                    }
                }
                else
                {

                    maxTop = -topAux;
                }
            }
            else
            {

                maxTop = ((float) (752 * 0.5) - (float) (heightStage * currentScaleFactor * 0.5));


                maxTop -= topAux;
            }


            savedMatrix.postTranslate(maxLeft, maxTop);


            previousScaleFactor = currentScaleFactor;

            invalidate();
            requestLayout();
        }
        else
        {
            firstTimeOnEvent = false;

            xInitial = detector.getFocusX();
            yInitial = detector.getFocusY();

            previousScaleFactor = currentScaleFactor;
        }

        float[] values = new float[9];
        savedMatrix.getValues(values);

        leftStage = values[Matrix.MTRANS_X];
        topStage = values[Matrix.MTRANS_Y];

        for (int i = 0; i < listeners.size(); i++)
        {
            listeners.get(i).onScale(detector);
        }

        atualizaParametrosView();

        return true;
    }
}

public boolean onDoubleTap(MotionEvent e)
{
    if (doubleTapZoomEnable)
    {
        currentScaleFactor = 1.0f;
        previousScaleFactor = 1.0f;

        savedMatrix.reset();

        xActual = 0;
        yActual = 0;
        xPrevious = 0;
        yPrevious = 0;
        savedMatrix.postTranslate(0, 0);

        invalidate();
        requestLayout();

        leftStage = 0;
        topStage = 0;

        for (int i = 0; i < listeners.size(); i++)
        {
            listeners.get(i).onDoubleTap(e);
        }
    }
    return true;
}

public boolean onDoubleTapEvent(MotionEvent e)
{
    for (int i = 0; i < listeners.size(); i++)
    {
        listeners.get(i).onDoubleTapEvent(e);
    }

    return false;
}

public boolean onSingleTapConfirmed(MotionEvent e)
{
    for (int i = 0; i < listeners.size(); i++)
    {
        listeners.get(i).onSingleTapConfirmed(e);
    }

    return false;
}


public boolean onDown(MotionEvent e)
{
    for (int i = 0; i < listeners.size(); i++)
    {
        listeners.get(i).onDown(e);
    }

    return false;
}

public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)
{
    for (int i = 0; i < listeners.size(); i++)
    {
        listeners.get(i).onFling(e1, e2, velocityX, velocityY);
    }

    return false;
}

public void onLongPress(MotionEvent e)
{
    for (int i = 0; i < listeners.size(); i++)
    {
        listeners.get(i).onLongPress(e);
    }
}

public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY)
{
    if (oneFingerMoveEnable && !onScale)
    {
        xPrevious = xActual;
        yPrevious = yActual;

        xActual = e2.getX() - diferenceFromScaleX;
        yActual = e2.getY() - diferenceFromScaleY;

        if (!firstTimeOnEvent)
        {
            float x = xActual - xPrevious;

            float y = yActual - yPrevious;

            savedMatrix.postTranslate(x, y);

            float[] values = new float[9];

            savedMatrix.getValues(values);

            float leftAux = (float) values[Matrix.MTRANS_X];
            float topAux = (float) values[Matrix.MTRANS_Y];

            float maxTop = 0;
            float maxLeft = 0;

            if (widthStage * currentScaleFactor >= 1280)
            {

                maxLeft = -((float) (widthStage * currentScaleFactor) - (float) 1280);

                if (leftAux < 0)
                {

                    if (leftAux < maxLeft)
                    {

                        maxLeft -= leftAux;
                    }
                    else
                    {

                        maxLeft = 0;
                    }
                }
                else
                {

                    maxLeft = -leftAux;
                }
            }
            else
            {

                maxLeft = ((float) (widthStage * 0.5) - (float) (widthStage * currentScaleFactor * 0.5));

                maxLeft -= leftAux;
            }

            if (heightStage * currentScaleFactor >= 752)
            {

                maxTop = -((float) (heightStage * currentScaleFactor) - (float) 752);

                if (topAux < 0)
                {

                    if (topAux < maxTop)
                    {

                        maxTop -= topAux;
                    }
                    else
                    {

                        maxTop = 0;
                    }
                }
                else
                {

                    maxTop = -topAux;
                }
            }
            else
            {

                maxTop = ((float) (752 * 0.5) - (float) (heightStage * currentScaleFactor * 0.5));


                maxTop -= topAux;
            }

            savedMatrix.postTranslate(maxLeft, maxTop);

            invalidate();
            requestLayout();
        }
        else
        {
            firstTimeOnEvent = false;

            xInitial = e2.getX() - diferenceFromScaleX;
            yInitial = e2.getY() - diferenceFromScaleY;
        }

        float[] values = new float[9];
        savedMatrix.getValues(values);

        leftStage = values[Matrix.MTRANS_X];
        topStage = values[Matrix.MTRANS_Y];
    }

    for (int i = 0; i < listeners.size(); i++)
    {
        listeners.get(i).onScroll(e1, e2, distanceX, distanceY);
    }

    atualizaParametrosView();

    return true;
}

private void atualizaParametrosView()
{

    RelativeLayout.LayoutParams params = (LayoutParams) this.getChildAt(0).getLayoutParams();

    params.width = widthStage;
    params.height = heightStage;

    this.getChildAt(0).setLayoutParams(params);

    params = (LayoutParams) this.getLayoutParams();

    params.width = widthStage;
    params.height = heightStage;

    this.setLayoutParams(params);

    ((View) this.getParent()).getLayoutParams().width = widthStage;
    ((View) this.getParent()).getLayoutParams().height = heightStage;
}

public void onShowPress(MotionEvent e)
{
    for (int i = 0; i < listeners.size(); i++)
    {
        listeners.get(i).onShowPress(e);
    }
}

public boolean onSingleTapUp(MotionEvent e)
{
    for (int i = 0; i < listeners.size(); i++)
    {
        listeners.get(i).onSingleTapUp(e);
    }

    return false;
}

// ===================================================================================
// ================================= GETTERS & SETTERS ===============================
// ===================================================================================

public float getScaleFactorActual()
{
    return currentScaleFactor;
}

public float getScaleFactorPrevious()
{
    return previousScaleFactor;
}

public float getxPrevious()
{
    return xPrevious;
}

public float getyPrevious()
{
    return yPrevious;
}

public float getxActual()
{
    return xActual;
}

public float getyActual()
{
    return yActual;
}

public float getLeftStage()
{
    return leftStage;
}

public float getTopStage()
{
    return topStage;
}

public float getxInitial()
{
    return xInitial;
}

public float getyInitial()
{
    return yInitial;
}

public float getMaxScale()
{
    return maxScale;
}

public void setMaxScale(float maxScale)
{
    this.maxScale = maxScale;
}

public float getMinScale()
{
    return minScale;
}

public void setMinScale(float minScale)
{
    this.minScale = minScale;
}

public int getWidthStage()
{
    return widthStage;
}

public void setWidthStage(int widthStage)
{
    this.widthStage = widthStage;
}

public int getHeightStage()
{
    return heightStage;
}

public void setHeightStage(int heightStage)
{
    this.heightStage = heightStage;
}

public boolean isZoomEnable()
{
    return zoomEnable;
}

public void setZoomEnable(boolean zoomEnable)
{
    this.zoomEnable = zoomEnable;
}

public boolean isOneFingerMoveEnable()
{
    return oneFingerMoveEnable;
}

public void setOneFingerMoveEnable(boolean oneFingerMoveEnable)
{
    this.oneFingerMoveEnable = oneFingerMoveEnable;
}

public boolean isTwoFingersMoveEnable()
{
    return twoFingersMoveEnable;
}

public void setTwoFingersMoveEnable(boolean twoFingersMoveEnable)
{
    this.twoFingersMoveEnable = twoFingersMoveEnable;
}

public boolean isDoubleTapZoomEnable()
{
    return doubleTapZoomEnable;
}

public void setDoubleTapZoomEnable(boolean doubleTapZoomEnable)
{
    this.doubleTapZoomEnable = doubleTapZoomEnable;
}

}

4

0 に答える 0