android - Android SurfaceView 捏缩放效果

标签 android surfaceview pinchzoom

我想缩放 SurfaceView 以便我们也可以使用视频播放器和相机。我搜索了很多但没有找到任何合适的指南。已经问了很多与此相关的问题但没有合适的我找到了解决方案。实际上,对于捏合缩放,我们使用 Matrix,但问题是 SurfaceView 不支持 Matrix。所以可以建议我如何执行此操作。我经历了 this用于 PinchZoom。

非常感谢您提供正确的指南。谢谢

最佳答案

您可以适当设置MarginLayoutParams。详情见下方源码

/**
 * sonle.evizi
 */
package com.philips.cl.insight;

import android.graphics.PointF;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewGroup.MarginLayoutParams;
import android.widget.FrameLayout;

public class PanAndZoomListener1 implements OnTouchListener {

    private enum Anchor {
        NONE, LEFT, TOP, RIGHT, BOTTOM, LEFT_TOP, TOP_RIGHT, RIGHT_BOTTOM, LEFT_BOTTOM
    }

    private static final float SPACE_ZOOM = 10f;
    private static final float SPACE_DRAG = 5f;
    private static final float ZOOM_MAX = 8f;
    private static final String TAG = "PanAndZoomListener";
    // We can be in one of these 3 states
    static final int CLICK = 0;
    static final int DRAG = 1;
    static final int ZOOM = 2;
    static final int NONE = 3;
    int mode = NONE;

    // Remember some things for zooming
    PointF start = new PointF();
    PointF midPoint = new PointF();
    float oldDist = 1f;
    MarginLayoutParams oldParams;

    LiveStreamingActivity liveStreamingActivity;
    View parentView;
    View child;

    public PanAndZoomListener1(FrameLayout containter, View surfaceView,
        LiveStreamingActivity liveStreamingActivity) {
        this.liveStreamingActivity = liveStreamingActivity;
        this.parentView = containter;
        this.child = surfaceView;
    }

    public boolean onTouch(View view, MotionEvent event) {
        // Handle touch events here...
        switch (event.getActionMasked()) {
        case MotionEvent.ACTION_DOWN:
            initDragInfo(view, event);
            Log.i(TAG, "======ACTION_DOWN - CLICK ======" + event.getActionIndex());
            mode = CLICK;
            break;

        case MotionEvent.ACTION_POINTER_DOWN:
            Log.i(TAG, "======ACTION_POINTER_1_DOWN======");
            oldDist = spacing(event.getX(0), event.getY(0), event.getX(1), event.getY(1));
            Log.i(TAG, "========oldDist:" + oldDist + "=========");
            if (oldDist < SPACE_ZOOM) {
                mode = NONE;
            } else {
                mode = ZOOM;
                initZoomInfo(view, event);
            }
            break;

        case MotionEvent.ACTION_POINTER_UP:
            mode = NONE;
            break;

        case MotionEvent.ACTION_UP:
            Log.i(TAG, "ACTION_UP");

            if (mode == CLICK) {
                Log.i(TAG, "mode= onTouchDitect");
                liveStreamingActivity.onTouchDitect();
            }
            mode = NONE;
            break;

        case MotionEvent.ACTION_MOVE:
            if (mode == CLICK) {
                if (spacing(start.x, start.y, event.getRawX(), event.getRawY()) >= SPACE_DRAG) {
                    mode = DRAG;
                } else {
                    Log.i(TAG, "======ACTION_MOVE - CLICK======");
                    break;
                }
            }

            if (mode == DRAG) {
                Log.i(TAG, "======ACTION_MOVE - DRAG======");
                doPan(event.getRawX() - start.x, event.getRawY() - start.y);
                break;
            }

            if (mode == ZOOM) {
                Log.i(TAG, "======ACTION_MOVE - ZOOM======");

                float newDist = spacing(event.getX(0), event.getY(0), event.getX(1), event.getY(1));
                if (newDist >= SPACE_ZOOM) {
                    doZoom(newDist);
                }
            }
            break;
        }
        return true; // indicate event was handled
    }

    private void initDragInfo(View view, MotionEvent event) {
        start.set(event.getRawX(), event.getRawY());
        // Initialize start motion info
        oldParams = new MarginLayoutParams((MarginLayoutParams) child.getLayoutParams());
        oldParams.width = child.getWidth();
        oldParams.height = child.getHeight();
    }

    // Caculate the space between two points
    private float spacing(float x0, float y0, float x1, float y1) {
        float x = x0 - x1;
        float y = y0 - y1;
        return (float) Math.sqrt(x * x + y * y);
    }

    // Calculate the mid point of the first two fingers
    private void initZoomInfo(View view, MotionEvent event) {
        midPoint.set((event.getX(0) + event.getX(1)) / 2, (event.getY(0) + event.getY(1)) / 2);

        // Initialize start motion info
        oldParams = new MarginLayoutParams((MarginLayoutParams) child.getLayoutParams());
        oldParams.width = child.getWidth();
        oldParams.height = child.getHeight();
    }

    public void doZoom(float newDist) {
        Anchor anchor = Anchor.NONE;
        /*
        Log.i(TAG, "=======MID POINT: " + midPoint.x + "; " + midPoint.y + "============");
        Log.i(TAG, "=======CHILD VIEW WIDTH: " + child.getWidth() + "============");
        */

        MarginLayoutParams childParams = (MarginLayoutParams) child.getLayoutParams();

        // Log.i(TAG, "=======CHILD VIEW LEFT MARGIN: " + childParams.leftMargin + "============");

        float scale = newDist / oldDist;

        int oriWidth = parentView.getWidth();
        int oriHeight = parentView.getHeight();
        float tempWidth = oldParams.width * scale;
        float tempHeight = tempWidth * oriHeight / oriWidth;

        if (tempWidth < oriWidth || tempWidth > oriWidth * ZOOM_MAX) {
            return;
        }

        childParams.width = (int) tempWidth;
        childParams.height = (int) tempHeight;

        float x1 = midPoint.x + oldParams.leftMargin;
        float x2 = oriWidth - x1;
        float y1 = midPoint.y + oldParams.topMargin;
        float y2 = oriHeight - y1;

        if (midPoint.x * scale <= x1) {
            anchor = Anchor.LEFT;
        } else if ((oldParams.width - midPoint.x) * scale <= x2) {
            anchor = Anchor.RIGHT;
        }

        if (midPoint.y * scale <= y1) {
            if (anchor == Anchor.LEFT) {
                anchor = Anchor.LEFT_TOP;
            } else if (anchor == Anchor.RIGHT) {
                anchor = Anchor.TOP_RIGHT;
            } else {
                anchor = Anchor.TOP;
            }
        } else if ((oldParams.height - midPoint.y) * scale <= y2) {
            if (anchor == Anchor.LEFT) {
                anchor = Anchor.LEFT_BOTTOM;
            } else if (anchor == Anchor.RIGHT) {
                anchor = Anchor.RIGHT_BOTTOM;
            } else {
                anchor = Anchor.BOTTOM;
            }
        }

        switch (anchor) {
        case BOTTOM:
            childParams.leftMargin = (int) (x1 - midPoint.x * scale);
            childParams.topMargin = (int) (oriHeight - tempHeight);
            break;
        case LEFT:
            childParams.leftMargin = 0;
            childParams.topMargin = (int) (y1 - midPoint.y * scale);
            break;
        case LEFT_BOTTOM:
            childParams.leftMargin = 0;
            childParams.topMargin = (int) (oriHeight - tempHeight);
            break;
        case LEFT_TOP:
            childParams.leftMargin = 0;
            childParams.topMargin = 0;
            break;
        case NONE:
            childParams.leftMargin = (int) (x1 - midPoint.x * scale);
            childParams.topMargin = (int) (y1 - midPoint.y * scale);
            break;
        case RIGHT:
            childParams.leftMargin = (int) (oriWidth - tempWidth);
            childParams.topMargin = (int) (y1 - midPoint.y * scale);
            break;
        case RIGHT_BOTTOM:
            childParams.leftMargin = (int) (oriWidth - tempWidth);
            childParams.topMargin = (int) (oriHeight - tempHeight);
            break;
        case TOP:
            childParams.leftMargin = (int) (x1 - midPoint.x * scale);
            childParams.topMargin = 0;
            break;
        case TOP_RIGHT:
            childParams.topMargin = 0;
            childParams.leftMargin = (int) (oriWidth - tempWidth);
            break;
        default:
            break;
        }

        child.setLayoutParams(childParams);
    }

    public void doPan(float panX, float panY) {
        Anchor anchor = Anchor.NONE;
        MarginLayoutParams childParams = (MarginLayoutParams) child.getLayoutParams();

        if (oldParams.width <= parentView.getWidth()) {
            return;
        }

        if (oldParams.leftMargin + panX >= 0) {
            anchor = Anchor.LEFT;
        } else if (oldParams.leftMargin + panX + oldParams.width <= parentView.getWidth()) {
            anchor = Anchor.RIGHT;
        }

        if (oldParams.topMargin + panY >= 0) {
            if (anchor == Anchor.LEFT) {
                anchor = Anchor.LEFT_TOP;
            } else if (anchor == Anchor.RIGHT) {
                anchor = Anchor.TOP_RIGHT;
            } else {
                anchor = Anchor.TOP;
            }
        } else if (oldParams.topMargin + panY + oldParams.height <= parentView.getHeight()) {
            if (anchor == Anchor.LEFT) {
                anchor = Anchor.LEFT_BOTTOM;
            } else if (anchor == Anchor.RIGHT) {
                anchor = Anchor.RIGHT_BOTTOM;
            } else {
                anchor = Anchor.BOTTOM;
            }
        }

        switch (anchor) {
        case BOTTOM:
        case TOP:
            childParams.leftMargin = (int) (oldParams.leftMargin + panX);
            break;
        case LEFT:
        case RIGHT:
            childParams.topMargin = (int) (oldParams.topMargin + panY);
            break;
        case NONE:
            childParams.topMargin = (int) (oldParams.topMargin + panY);
            childParams.leftMargin = (int) (oldParams.leftMargin + panX);
            break;
        case LEFT_BOTTOM:
        case LEFT_TOP:
        case RIGHT_BOTTOM:
        case TOP_RIGHT:
            break;
        default:
            break;
        }
        child.setLayoutParams(childParams);
    }
}

关于android - Android SurfaceView 捏缩放效果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16121145/

相关文章:

android - 从特定浏览器启动 android 应用程序

android - 如何在不将录音保存到文件的情况下启动 android mediarecorder?

Android SurfaceView 宽度/高度

android - SurfaceView onDraw 模仿用户减速运动

android - 缩放图像(Android Studio)

java - 如果语句: Compare multiple ints

android - 在 Kotlin 中固定列表大小的最佳方法是什么

android - 启动 Activity 时出错

c# - 使用 Unity 5 UI 进行双指缩放

javascript - PinchZoom.js 与 iOS 设备上的 Owl Carousel 不兼容