在 SurfaceView 上捏缩放 [英] Pinch zoom on SurfaceView

查看:59
本文介绍了在 SurfaceView 上捏缩放的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在 SurfaceView 上实现双指缩放.我对此进行了大量研究,我发现

<小时>

编辑 2: 在尝试其他方法后,我遇到了一个新问题 -

我将 ZoomLayout 完全更改为以下内容:

public class ZoomableSurfaceView extends SurfaceView {私人 ScaleGestureDetector SGD;私有上下文上下文;私有布尔值 isSingleTouch;私人浮动宽度,高度= 0;私人浮动比例= 1f;私人浮动 minScale = 1f;私人浮动 maxScale = 5f;int 左、上、右、下;公共 ZoomableSurfaceView(上下文上下文){超级(上下文);this.context = 上下文;在里面();}公共 ZoomableSurfaceView(上下文上下文,AttributeSet attrs){超级(上下文,属性);this.context = 上下文;在里面();}公共 ZoomableSurfaceView(上下文上下文,AttributeSet attrs,int defStyleAttr){超级(上下文,属性,defStyleAttr);this.context = 上下文;在里面();}私有无效初始化(){setOnTouchListener(new MyTouchListeners());SGD = new ScaleGestureDetector(context, new ScaleListener());this.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {@覆盖公共无效 onGlobalLayout() {}});}@覆盖protected void onLayout(boolean 改变,int left,int top,int right,int bottom) {super.onLayout(改变,左,上,右,下);如果(宽度 == 0 && 高度 == 0){宽度 = ZoomableSurfaceView.this.getWidth();高度 = ZoomableSurfaceView.this.getHeight();this.left = 左;this.right = 正确;this.top = 顶部;this.bottom = 底部;}}私有类 MyTouchListeners 实现 View.OnTouchListener {浮动 dX,dY;MyTouchListeners() {极好的();}@覆盖公共布尔 onTouch(查看视图,MotionEvent 事件){SGD.onTouchEvent(事件);如果 (event.getPointerCount() > 1) {isSingleTouch = 假;} 别的 {if (event.getAction() == MotionEvent.ACTION_UP) {isSingleTouch = 真;}}开关(事件.getAction()){案例 MotionEvent.ACTION_DOWN:dX = ZoomableSurfaceView.this.getX() - event.getRawX();dY = ZoomableSurfaceView.this.getY() - event.getRawY();休息;案例 MotionEvent.ACTION_MOVE:如果(isSingleTouch){ZoomableSurfaceView.this.animate().x(event.getRawX() + dX).y(event.getRawY() + dY).setDuration(0).开始();checkDimension(ZoomableSurfaceView.this);}休息;默认:返回真;}返回真;}}私有类 ScaleListener 扩展 ScaleGestureDetector.SimpleOnScaleGestureListener {@覆盖公共布尔 onScale(ScaleGestureDetector 检测器){//Log.e("onGlobalLayout: ", scale + " " + width + " " + height);scale *=detector.getScaleFactor();scale = Math.max(minScale, Math.min(scale, maxScale));FrameLayout.LayoutParams params = new FrameLayout.LayoutParams((int) (width * scale), (int) (height * scale));Log.e("onGlobalLayout: ", (int) (width * scale) + " " + (int) (height * scale));ZoomableSurfaceView.this.setLayoutParams(params);checkDimension(ZoomableSurfaceView.this);返回真;}}私有无效检查维度(查看 vi){如果(vi.getX()>左){vi.animate().x(左).y(vi.getY()).setDuration(0).开始();}if ((vi.getWidth() + vi.getX()) < right) {vi.animate().x(右 - vi.getWidth()).y(vi.getY()).setDuration(0).开始();}如果(vi.getY()>顶部){vi.animate().x(vi.getX()).y(顶部).setDuration(0).开始();}如果 ((vi.getHeight() + vi.getY()) <底部) {vi.animate().x(vi.getX()).y(底部 - vi.getHeight()).setDuration(0).开始();}}}

我现在面临的问题是它会缩放到 X - 0 和 Y - 0,这意味着它会缩放到屏幕的左上角,而不是缩放到我手指之间的点.. 我想这可能是与以下相关:

@Override公共布尔 onScale(ScaleGestureDetector 检测器){//Log.e("onGlobalLayout: ", scale + " " + width + " " + height);scale *=detector.getScaleFactor();scale = Math.max(minScale, Math.min(scale, maxScale));FrameLayout.LayoutParams params = new FrameLayout.LayoutParams((int) (width * scale), (int) (height * scale));Log.e("onGlobalLayout: ", (int) (width * scale) + " " + (int) (height * scale));ZoomableSurfaceView.this.setLayoutParams(params);checkDimension(ZoomableSurfaceView.this);返回真;}

我有一个想法,我应该检测 2 个手指的中心点并将其添加到 OnScale.我应该如何进行?

<小时>

编辑 3:

好的,我终于让变焦在运行 Nougat 的 J7 Pro 上完美运行.但现在的问题是,我在运行 Lollipop 的 S4 中的 SurfaceView 没有被放大,而是我的 SurfaceView 被移到了左上角.我已经测试在我的自定义缩放视图中放置一个 ImageView 并且图像像预期的那样完美地缩放.这就是我的自定义缩放类现在的样子:

public class ZoomLayout extends FrameLayout 实现 ScaleGestureDetector.OnScaleGestureListener {私有枚举模式{没有任何,拖,飞涨}private static final String TAG = "ZoomLayout";私有静态最终浮点 MIN_ZOOM = 1.0f;私有静态最终浮动 MAX_ZOOM = 4.0f;私人模式模式= Mode.NONE;私人浮动比例= 1.0f;私人浮动 lastScaleFactor = 0f;//手指第一次接触屏幕的地方私人浮动 startX = 0f;私人浮动 startY = 0f;//翻译画布多少私人浮动 dx = 0f;私人浮动 dy = 0f;私人浮动 prevDx = 0f;私人浮动 prevDy = 0f;公共缩放布局(上下文上下文){超级(上下文);初始化(上下文);}公共缩放布局(上下文上下文,属性集属性){超级(上下文,属性);初始化(上下文);}public ZoomLayout(上下文上下文,AttributeSet attrs,int defStyle){超级(上下文,属性,defStyle);初始化(上下文);}私有无效初始化(上下文上下文){最终 ScaleGestureDetector scaleDetector = new ScaleGestureDetector(context, this);setOnTouchListener(new View.OnTouchListener() {@覆盖公共布尔onTouch(视图视图,MotionEventmotionEvent){开关 (motionEvent.getAction() & MotionEvent.ACTION_MASK) {案例 MotionEvent.ACTION_DOWN:Log.i(TAG, "DOWN");如果(比例> MIN_ZOOM){模式 = 模式.DRAG;startX = motionEvent.getX() - prevDx;startY = motionEvent.getY() - prevDy;}休息;案例 MotionEvent.ACTION_MOVE:if (mode == Mode.DRAG) {dx = motionEvent.getX() - startX;dy = motionEvent.getY() - startY;}休息;案例 MotionEvent.ACTION_POINTER_DOWN:mode = Mode.ZOOM;休息;案例 MotionEvent.ACTION_POINTER_UP:mode = Mode.NONE;//从 DRAG 更改,弄乱了缩放休息;案例 MotionEvent.ACTION_UP:Log.i(TAG, "UP");mode = Mode.NONE;prevDx = dx;上一个 = dy;休息;}scaleDetector.onTouchEvent(motionEvent);if ((mode == Mode.DRAG && scale >= MIN_ZOOM) || mode == Mode.ZOOM) {getParent().requestDisallowInterceptTouchEvent(true);float maxDx = child().getWidth() * (scale - 1);//调整为零枢轴float maxDy = child().getHeight() * (scale - 1);//调整为零枢轴dx = Math.min(Math.max(dx, -maxDx), 0);//调整为零枢轴dy = Math.min(Math.max(dy, -maxDy), 0);//调整为零枢轴Log.i(TAG, "Width: " + child().getWidth() + ", scale " + scale + ", dx " + dx+ ", 最大 " + maxDx);applyScaleAndTranslation();}返回真;}});}//缩放手势检测器@覆盖公共布尔 onScaleBegin(ScaleGestureDetector scaleDetector) {Log.i(TAG, "onScaleBegin");返回真;}@覆盖公共布尔 onScale(ScaleGestureDetector scaleDetector){浮动比例因子 = scaleDetector.getScaleFactor();Log.i(TAG, "onScale(), scaleFactor = " + scaleFactor);if (lastScaleFactor == 0 || (Math.signum(scaleFactor) == Math.signum(lastScaleFactor))) {浮动 prevScale = 比例;比例 *= 比例因子;scale = Math.max(MIN_ZOOM, Math.min(scale, MAX_ZOOM));lastScaleFactor = scaleFactor;浮动调整比例因子 = 比例/prevScale;//添加逻辑来调整捏/缩放枢轴点的 dx 和 dyLog.d(TAG, "onScale,adjustedScaleFactor = " +adjustedScaleFactor);Log.d(TAG, "onScale, BEFORE dx/dy = " + dx + "/" + dy);float focusX = scaleDetector.getFocusX();float focusY = scaleDetector.getFocusY();Log.d(TAG, "onScale, focusX/focusy = " + focusX + "/" + focusY);dx += (dx - focusX) * (adjustedScaleFactor - 1);dy += (dy - focusY) * (adjustedScaleFactor - 1);Log.d(TAG, "onScale, dx/dy = " + dx + "/" + dy);} 别的 {lastScaleFactor = 0;}返回真;}@覆盖公共无效onScaleEnd(ScaleGestureDetector scaleDetector){Log.i(TAG, "onScaleEnd");}私有无效 applyScaleAndTranslation() {child().setScaleX(scale);child().setScaleY(scale);child().setPivotX(0f);//默认是在视图中心旋转child().setPivotY(0f);//默认是在视图中心旋转child().setTranslationX(dx);child().setTranslationY(dy);}私人视图子(){返回 getChildAt(0);}

<小时>

编辑 4:添加了行为视频:

请查看更新我的 zoomLayout 类以编辑 3 后当前缩放的样子 -

SurfaceView 缩放行为视频

解决方案

不要使用 SurfaceView,而是使用 TextureView ,它具有更多功能,优于 SurfaceView.请参阅 TextureView 文档

<小时>

您的代码确实是正确的并且应该可以工作,但在某些情况下,在 SurfaceView 上绘制的 MediaPlayer 不会调整大小,并且会产生在该位置发生缩放的错觉0,0 的电话.如果为 SurfaceView 设置小于父级的大小并为父级设置背景,你会注意到这一点

<小时>

代码中的解决方案

示例项目:双指缩放

项目扩展了TextureView,实现了触摸创建缩放效果.

图片:演示

I'm trying to implement pinch zoom on a SurfaceView. I've done a lot of research regarding this and I found this class to implement pinch zoom. Here is how I modified it:

public class ZoomLayout extends FrameLayout implements ScaleGestureDetector.OnScaleGestureListener {

private SurfaceView mSurfaceView;

private enum Mode {
    NONE,
    DRAG,
    ZOOM
}

private static final String TAG = "ZoomLayout";
private static final float MIN_ZOOM = 1.0f;
private static final float MAX_ZOOM = 4.0f;

private Mode mode;
private float scale = 1.0f;
private float lastScaleFactor = 0f;

// Where the finger first  touches the screen
private float startX = 0f;
private float startY = 0f;

// How much to translate the canvas
private float dx = 0f;
private float dy = 0f;
private float prevDx = 0f;
private float prevDy = 0f;

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

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

public ZoomLayout(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    init(context);
}

private void init(Context context) {
    final ScaleGestureDetector scaleDetector = new ScaleGestureDetector(context, this);
    setOnTouchListener(new OnTouchListener() {
        public boolean onTouch(View view, MotionEvent motionEvent) {
            ZoomLayout.this.mSurfaceView = (SurfaceView) view.findViewById(R.id.mSurfaceView);

            switch (motionEvent.getAction() & MotionEvent.ACTION_MASK) {
                case MotionEvent.ACTION_DOWN:
                    Log.i(TAG, "DOWN");
                    if (scale > MIN_ZOOM) {
                        mode = Mode.DRAG;
                        startX = motionEvent.getX() - prevDx;
                        startY = motionEvent.getY() - prevDy;
                    }
                    break;
                case MotionEvent.ACTION_MOVE:
                    if (mode == Mode.DRAG) {
                        dx = motionEvent.getX() - startX;
                        dy = motionEvent.getY() - startY;
                    }
                    break;
                case MotionEvent.ACTION_POINTER_DOWN:
                    mode = Mode.ZOOM;
                    break;
                case MotionEvent.ACTION_POINTER_UP:
                    mode = Mode.NONE;
                    break;
                case MotionEvent.ACTION_UP:
                    Log.i(TAG, "UP");
                    mode = Mode.NONE;
                    prevDx = dx;
                    prevDy = dy;
                    break;
            }
            scaleDetector.onTouchEvent(motionEvent);

            if ((mode == Mode.DRAG && scale >= MIN_ZOOM) || mode == Mode.ZOOM) {
                getParent().requestDisallowInterceptTouchEvent(true);
                float maxDx = (child().getWidth() - (child().getWidth() / scale)) / 2 * scale;
                float maxDy = (child().getHeight() - (child().getHeight() / scale))/ 2 * scale;
                dx = Math.min(Math.max(dx, -maxDx), maxDx);
                dy = Math.min(Math.max(dy, -maxDy), maxDy);
                Log.i(TAG, "Width: " + child().getWidth() + ", scale " + scale + ", dx " + dx
                        + ", max " + maxDx);
                applyScaleAndTranslation();
            }

            return true;
        }
    });
}

// ScaleGestureDetector

public boolean onScaleBegin(ScaleGestureDetector scaleDetector) {
    Log.i(TAG, "onScaleBegin");
    return true;
}

public boolean onScale(ScaleGestureDetector scaleDetector) {
    float scaleFactor = scaleDetector.getScaleFactor();
    Log.i(TAG, "mode:" + this.mode + ", onScale:" + scaleFactor);
    if (this.lastScaleFactor == 0.0f || Math.signum(scaleFactor) == Math.signum(this.lastScaleFactor)) {
        this.scale *= scaleFactor;
        this.scale = Math.max(MIN_ZOOM, Math.min(this.scale, MAX_ZOOM));
        this.lastScaleFactor = scaleFactor;
    } else {
        this.lastScaleFactor = 0.0f;
    }
    if (this.mSurfaceView != null) {
        int orgWidth = getWidth();
        int _width = (int) (((float) orgWidth) * this.scale);
        int _height = (int) (((float) getHeight()) * this.scale);
        LayoutParams params = (LayoutParams) this.mSurfaceView.getLayoutParams();
        params.height = _height;
        params.width = _width;
        this.mSurfaceView.setLayoutParams(params);
        child().setScaleX(this.scale);
        child().setScaleY(this.scale);
    }
    return true;
}

@Override
public void onScaleEnd(ScaleGestureDetector scaleDetector) {
    Log.i(TAG, "onScaleEnd");
}

private void applyScaleAndTranslation() {
    child().setScaleX(scale);
    child().setScaleY(scale);
    child().setTranslationX(dx);
    child().setTranslationY(dy);
}

private View child() {
    return getChildAt(0);
}

and I implement it into my layout like this:

<pacageName.control.ZoomLayout
    android:id="@+id/mZoomLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:measureAllChildren="true">

        <SurfaceView
            android:id="@+id/mSurfaceView"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

</pacageName.control.ZoomLayout>

The problem I'm having is that the zoom is not 'smooth' and the behavior of the zoom is different in different devices (Samsung S4 (Lollipop) and J7Pro (Nougat)).

I'm not sure why pinch zoom is "glitchy" and why it doesn't zoom the same way on the two different devices.


Edit 1: Memory and CPU consumption image added below -


EDIT 2: After trying something else I'm facing a new issue -

I changed my ZoomLayout completely to the following:

public class ZoomableSurfaceView extends SurfaceView {

private ScaleGestureDetector SGD;
private Context context;
private boolean isSingleTouch;
private float width, height = 0;
private float scale = 1f;
private float minScale = 1f;
private float maxScale = 5f;
int left, top, right, bottom;

public ZoomableSurfaceView(Context context) {
    super(context);
    this.context = context;
    init();
}

public ZoomableSurfaceView(Context context, AttributeSet attrs) {
    super(context, attrs);
    this.context = context;
    init();
}

public ZoomableSurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    this.context = context;
    init();
}

private void init() {
    setOnTouchListener(new MyTouchListeners());
    SGD = new ScaleGestureDetector(context, new ScaleListener());
    this.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {

        }
    });
}

@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
    super.onLayout(changed, left, top, right, bottom);
    if (width == 0 && height == 0) {
        width = ZoomableSurfaceView.this.getWidth();
        height = ZoomableSurfaceView.this.getHeight();
        this.left = left;
        this.right = right;
        this.top = top;
        this.bottom = bottom;
    }

}

private class MyTouchListeners implements View.OnTouchListener {

    float dX, dY;

    MyTouchListeners() {
        super();
    }

    @Override
    public boolean onTouch(View view, MotionEvent event) {
        SGD.onTouchEvent(event);
        if (event.getPointerCount() > 1) {
            isSingleTouch = false;
        } else {
            if (event.getAction() == MotionEvent.ACTION_UP) {
                isSingleTouch = true;
            }
        }
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                dX = ZoomableSurfaceView.this.getX() - event.getRawX();
                dY = ZoomableSurfaceView.this.getY() - event.getRawY();
                break;

            case MotionEvent.ACTION_MOVE:
                if (isSingleTouch) {
                    ZoomableSurfaceView.this.animate()
                            .x(event.getRawX() + dX)
                            .y(event.getRawY() + dY)
                            .setDuration(0)
                            .start();
                    checkDimension(ZoomableSurfaceView.this);
                }
                break;
            default:
                return true;
        }
        return true;
    }
}

private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
    @Override
    public boolean onScale(ScaleGestureDetector detector) {
        //Log.e("onGlobalLayout: ", scale + " " + width + " " + height);
        scale *= detector.getScaleFactor();
        scale = Math.max(minScale, Math.min(scale, maxScale));
        FrameLayout.LayoutParams params = new FrameLayout.LayoutParams((int) (width * scale), (int) (height * scale));
        Log.e("onGlobalLayout: ", (int) (width * scale) + " " + (int) (height * scale));
        ZoomableSurfaceView.this.setLayoutParams(params);
        checkDimension(ZoomableSurfaceView.this);
        return true;
    }
}

private void checkDimension(View vi) {
    if (vi.getX() > left) {
        vi.animate()
                .x(left)
                .y(vi.getY())
                .setDuration(0)
                .start();
    }

    if ((vi.getWidth() + vi.getX()) < right) {
        vi.animate()
                .x(right - vi.getWidth())
                .y(vi.getY())
                .setDuration(0)
                .start();
    }

    if (vi.getY() > top) {
        vi.animate()
                .x(vi.getX())
                .y(top)
                .setDuration(0)
                .start();
    }

    if ((vi.getHeight() + vi.getY()) < bottom) {
        vi.animate()
                .x(vi.getX())
                .y(bottom - vi.getHeight())
                .setDuration(0)
                .start();
    }
}
}

The problem I'm facing now is that it zooms to X - 0 and Y - 0 meaning that it zooms to the top-left of the screen instead of zooming to the point between my fingers.. I think it could be related to the following:

@Override
    public boolean onScale(ScaleGestureDetector detector) {
        //Log.e("onGlobalLayout: ", scale + " " + width + " " + height);
        scale *= detector.getScaleFactor();
        scale = Math.max(minScale, Math.min(scale, maxScale));
        FrameLayout.LayoutParams params = new FrameLayout.LayoutParams((int) (width * scale), (int) (height * scale));
        Log.e("onGlobalLayout: ", (int) (width * scale) + " " + (int) (height * scale));
        ZoomableSurfaceView.this.setLayoutParams(params);
        checkDimension(ZoomableSurfaceView.this);
        return true;
    }

I have an idea that I should detect the centre point of the 2 fingers and add that to OnScale. How should I proceed?


EDIT 3:

Ok I finally got the zoom working perfectly on my J7 Pro running Nougat. But the problem now, is that my SurfaceView in my S4 running Lollipop doesn't get zoomed in, instead my SurfaceView gets moved to the top left corner. I have tested placing a ImageView inside my custom zoomview and the image gets zoomed perfectly like expected. This is how my custom zoom class looks like now:

public class ZoomLayout extends FrameLayout implements ScaleGestureDetector.OnScaleGestureListener {

private enum Mode {
    NONE,
    DRAG,
    ZOOM
}

private static final String TAG = "ZoomLayout";
private static final float MIN_ZOOM = 1.0f;
private static final float MAX_ZOOM = 4.0f;

private Mode mode = Mode.NONE;
private float scale = 1.0f;
private float lastScaleFactor = 0f;

// Where the finger first  touches the screen
private float startX = 0f;
private float startY = 0f;

// How much to translate the canvas
private float dx = 0f;
private float dy = 0f;
private float prevDx = 0f;
private float prevDy = 0f;

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

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

public ZoomLayout(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    init(context);
}

private void init(Context context) {
    final ScaleGestureDetector scaleDetector = new ScaleGestureDetector(context, this);
    setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View view, MotionEvent motionEvent) {
            switch (motionEvent.getAction() & MotionEvent.ACTION_MASK) {
                case MotionEvent.ACTION_DOWN:
                    Log.i(TAG, "DOWN");
                    if (scale > MIN_ZOOM) {
                        mode = Mode.DRAG;
                        startX = motionEvent.getX() - prevDx;
                        startY = motionEvent.getY() - prevDy;
                    }
                    break;
                case MotionEvent.ACTION_MOVE:
                    if (mode == Mode.DRAG) {
                        dx = motionEvent.getX() - startX;
                        dy = motionEvent.getY() - startY;
                    }
                    break;
                case MotionEvent.ACTION_POINTER_DOWN:
                    mode = Mode.ZOOM;
                    break;
                case MotionEvent.ACTION_POINTER_UP:
                    mode = Mode.NONE; // changed from DRAG, was messing up zoom
                    break;
                case MotionEvent.ACTION_UP:
                    Log.i(TAG, "UP");
                    mode = Mode.NONE;
                    prevDx = dx;
                    prevDy = dy;
                    break;
            }
            scaleDetector.onTouchEvent(motionEvent);

            if ((mode == Mode.DRAG && scale >= MIN_ZOOM) || mode == Mode.ZOOM) {
                getParent().requestDisallowInterceptTouchEvent(true);
                float maxDx = child().getWidth() * (scale - 1);  // adjusted for zero pivot
                float maxDy = child().getHeight() * (scale - 1);  // adjusted for zero pivot
                dx = Math.min(Math.max(dx, -maxDx), 0);  // adjusted for zero pivot
                dy = Math.min(Math.max(dy, -maxDy), 0);  // adjusted for zero pivot
                Log.i(TAG, "Width: " + child().getWidth() + ", scale " + scale + ", dx " + dx
                        + ", max " + maxDx);
                applyScaleAndTranslation();
            }

            return true;
        }
    });
}

// ScaleGestureDetector
@Override
public boolean onScaleBegin(ScaleGestureDetector scaleDetector) {
    Log.i(TAG, "onScaleBegin");
    return true;
}

@Override
public boolean onScale(ScaleGestureDetector scaleDetector) {
    float scaleFactor = scaleDetector.getScaleFactor();
    Log.i(TAG, "onScale(), scaleFactor = " + scaleFactor);
    if (lastScaleFactor == 0 || (Math.signum(scaleFactor) == Math.signum(lastScaleFactor))) {
        float prevScale = scale;
        scale *= scaleFactor;
        scale = Math.max(MIN_ZOOM, Math.min(scale, MAX_ZOOM));
        lastScaleFactor = scaleFactor;
        float adjustedScaleFactor = scale / prevScale;
        // added logic to adjust dx and dy for pinch/zoom pivot point
        Log.d(TAG, "onScale, adjustedScaleFactor = " + adjustedScaleFactor);
        Log.d(TAG, "onScale, BEFORE dx/dy = " + dx + "/" + dy);
        float focusX = scaleDetector.getFocusX();
        float focusY = scaleDetector.getFocusY();
        Log.d(TAG, "onScale, focusX/focusy = " + focusX + "/" + focusY);
        dx += (dx - focusX) * (adjustedScaleFactor - 1);
        dy += (dy - focusY) * (adjustedScaleFactor - 1);
        Log.d(TAG, "onScale, dx/dy = " + dx + "/" + dy);
    } else {
        lastScaleFactor = 0;
    }
    return true;
}

@Override
public void onScaleEnd(ScaleGestureDetector scaleDetector) {
    Log.i(TAG, "onScaleEnd");
}

private void applyScaleAndTranslation() {
    child().setScaleX(scale);
    child().setScaleY(scale);
    child().setPivotX(0f);  // default is to pivot at view center
    child().setPivotY(0f);  // default is to pivot at view center
    child().setTranslationX(dx);
    child().setTranslationY(dy);
}

private View child() {
    return getChildAt(0);
}


Edit 4: Added video of behaviour:

Please see how the current zoom looks like after updating my zoomLayout class to edit 3 -

Video of SurfaceView zoom behaviour

解决方案

Instead of using SurfaceView, use TextureView which has more features and is preferred over SurfaceView. See TextureView Documentation


Your code is indeed right and should work but in some cases, The MediaPlayer drawn on the SurfaceView does not resize and makes an illusion of the zoom happening at the position 0,0 of the phone. If you set a size smaller than the parent for the SurfaceView and set a background for the parent, you will notice this


SOLUTION IN CODE

Sample Project: Pinch Zoom

The project extends the TextureView and implements the touch to create the zoom effect.

IMAGE: DEMONSTRATION

这篇关于在 SurfaceView 上捏缩放的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆