相机preVIEW和API的GoogleMaps查看V2之间的Andr​​oid SurfaceView冲突 [英] Android SurfaceView conflict between CameraPreview and GoogleMaps API v2 View

查看:233
本文介绍了相机preVIEW和API的GoogleMaps查看V2之间的Andr​​oid SurfaceView冲突的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的应用程序有一组托管FragmentActivity的标签。有些选项卡包含的GoogleMaps API V2支持MapFragment和/或图形页面和另一个单一个是QR扫描。

我现在面临的问题是,如果你正在查看一个选项卡上SupportMapFragment或图形页面,然后切换到扫描仪选项卡中,SurfaceView仍交由previous SupportMapFragment /图形页面(当然,除非片断/查看被前选择扫描仪选项卡)中删除。这不是一个问题,直到试图将的GoogleMaps API V2,过V1,由于SurfaceView使用。

我不完全知道如何解决这个问题,我当扫描仪选项卡,并在相机preVIEW开始思考着清算的SurfaceView线的东西?而实现这一目标用帆布不知何故?
但是,我没有很多知识的SurfaceView类。

附件是用来处理扫描选项卡上的Andr​​oid相机我的相机preVIEW级。该的GoogleMaps API V2类只是由谷歌提供的基本设置,没什么特别的。

感谢您的时间和帮助。

 类相机preVIEW延伸的ViewGroup实现SurfaceHolder.Callback {
    私人最终字符串标记=镜头preVIEW    SurfaceView mSurfaceView;
    SurfaceHolder mHolder;
    尺寸M previewSize;
    清单<尺寸和GT; mSupported previewSizes;
    相机mCamera;
    previewCallback米previewCallback;
    AutoFocusCallback mAutoFocusCallback;    相机preVIEW(上下文的背景下,previewCallback previewCallback,AutoFocusCallback autoFocusCb){
        超级(上下文);        米previewCallback = previewCallback;
        mAutoFocusCallback = autoFocusCb;
        mSurfaceView =新SurfaceView(背景);
        addView(mSurfaceView);        //安装SurfaceHolder.Callback所以我们得到通知时,
        //创建下垫面和销毁。
        mHolder = mSurfaceView.getHolder();
        mHolder.addCallback(本);
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);    }    公共无效setCamera(相机摄像机){
        mCamera =摄像头;
        如果(mCamera!= NULL){
            mSupported previewSizes = mCamera.getParameters()getSupported previewSizes()。
            requestLayout();
        }
    }    @覆盖
    保护无效onMeasure(INT widthMeasureSpec,诠释heightMeasureSpec){
        //我们故意忽略孩子的测量,因为充当
        //封装到中心相机preVIEW而不是SurfaceView
        //伸展它。
        最终诠释宽度= resolveSize(getSuggestedMinimumWidth(),widthMeasureSpec);
        最终诠释身高= resolveSize(getSuggestedMinimumHeight(),heightMeasureSpec);
        setMeasuredDimension(宽度,高度);        如果(mSupported previewSizes!= NULL){
            米previewSize = getOptimal previewSize(mSupported previewSizes,宽,高);
        }
    }    @覆盖
    保护无效onLayout(布尔变化,诠释L,INT T,INT R,INT B){
        如果(变更&放大器;&放大器; getChildCount()大于0){
            最后查看孩子= getChildAt(0);            最终诠释宽度= R - 1;
            最终诠释身高= B - 吨;            INT previewWidth =宽度;
            INT previewHeight =高度;
            如果(M previewSize!= NULL){
                previewWidth = M previewSize.width;
                previewHeight = M previewSize.height;
            }            //中心父项子SurfaceView。
            如果(宽* previewHeight>高* previewWidth){
                最终诠释scaledChildWidth = previewWidth *高/ previewHeight;
                child.layout(0,0,宽度,高度);
            }其他{
                最终诠释scaledChildHeight = previewHeight *宽/ previewWidth;
                child.layout(0,0,宽度,高度);            }
        }
    }    公共无效surfaceCreated(SurfaceHolder持有人){        //表面有被创建,获取摄像机,并告诉它在哪里
        //绘制。
        尝试{
            如果(mCamera!= NULL){
                mCamera.set previewDisplay(支架);
                mCamera.setDisplayOrientation(90);
            }
        }赶上(IOException异常除外){
            Log.e(TAG,IOException异常造成集previewDisplay()除外);
        }
    }    公共无效surfaceDestroyed(SurfaceHolder持有人){
        //当我们回到地面就会被破坏,因此停止preVIEW。
        如果(mCamera!= NULL){
            mCamera.stop preVIEW();
        }
    }
    私人尺寸getOptimal previewSize(列表<尺寸和GT;的大小,INT W,INT高){
        最终双ASPECT_TOLERANCE = 0.1;
        双targetRatio =(双)W / H;
        如果(大小== NULL)返回NULL;        大小optimalSize = NULL;
        双minDiff = Double.MAX_VALUE;        INT targetHeight = H;        //尝试找到一个大小匹配纵横比和尺寸
        对于(尺寸大小:大小){
            双率=(双)size.width / size.height;
            如果(Math.abs(比 - targetRatio)GT; ASPECT_TOLERANCE)继续;
            如果(Math.abs(size.height - targetHeight)LT; minDiff){
                optimalSize =大小;
                minDiff = Math.abs(size.height - targetHeight);
            }
        }        //找不到一个长宽比匹配,忽略此要求
        如果(optimalSize == NULL){
            minDiff = Double.MAX_VALUE;
            对于(尺寸大小:大小){
                如果(Math.abs(size.height - targetHeight)LT; minDiff){
                    optimalSize =大小;
                    minDiff = Math.abs(size.height - targetHeight);
                }
            }
        }
        返回optimalSize;
    }    公共无效surfaceChanged(SurfaceHolder架,INT格式,诠释W,INT高){
        如果(holder.getSurface()== NULL){
            // preVIEW表面不存在
            返回;
        }        //现在,尺寸是已知的,设置相机参数,并开始
        //将preVIEW。
        如果(mCamera!= NULL){
            Camera.Parameters参数= mCamera.getParameters();            parameters.set previewSize(M previewSize.width,男previewSize.height);
            requestLayout();            mCamera.setParameters(参数);
            mCamera.set previewCallback(M previewCallback);
            mCamera.start preVIEW();
            mCamera.autoFocus(mAutoFocusCallback);
        }
    }}


解决方案

我遇到了同样的问题,一些前几天,我需要显示在GoogleMap的V2顶部的摄像头preVIEW看法,以下是我的解决方案,希望它可以帮助你。

  //构建一个摄像头preVIEW布局则显示它,或删除它,然后隐藏
    popCamera.setOnClickListener(新OnClickListener(){
        @覆盖
        公共无效的onClick(视图v){
            如果(cameraBar.getVisibility()== View.VISIBLE){
                cameraBar.removeAllViews();
                cameraBar.setVisibility(View.INVISIBLE);
            }否则如果(cameraBar.getVisibility()== View.INVISIBLE){
                //新相机表面视图,然后添加到preVIEW区
                如果(cameraSurfaceView == NULL){
                    cameraSurfaceView =新CameraSurfaceView(getApplicationContext());
                    // ===关键点===
                    ** cameraSurfaceView.setZOrderOnTop(真)**
                    LinearLayout.LayoutParams参数=新LinearLayout.LayoutParams(
                            LinearLayout.LayoutParams.MATCH_PARENT,
                            LinearLayout.LayoutParams.MATCH_PARENT);
                    previewArea.addView(cameraSurfaceView,参数);
                }                cameraBar.removeAllViews();                cameraBar.addView(previewArea);
                cameraBar.addView(snapArea);
                cameraBar.setVisibility(View.VISIBLE);
            }
        }
    });

My application has a set of tabs hosting FragmentActivity's. Some of these tabs contain a GoogleMaps Api v2 Support MapFragment and/or MapView and another single one is a QR scanner.

The problem I am facing is that if you are currently viewing a SupportMapFragment or MapView on one tab, and then switch to the Scanner tab, the SurfaceView is still taken over by the previous SupportMapFragment / MapView (unless of course the Fragment/View is removed prior to selecting the Scanner tab). This was not a problem until trying to incorporate GoogleMaps Api v2, over v1, due to the SurfaceView use.

I'm not entirely sure how to address this problem, I am thinking something along the lines of "clearing" the SurfaceView when the Scanner tab is selected and the CameraPreview is started? And achieve this using a canvas somehow? But I do not have a lot of knowledge on the SurfaceView class.

Attached is my "CameraPreview" class which is used to handle the Android Camera on the Scanner tab. The GoogleMaps api v2 class is just the basic setup provided by Google, nothing special.

Thank you for your time and help.

class CameraPreview extends ViewGroup implements SurfaceHolder.Callback {
    private final String TAG = "CameraPreview";

    SurfaceView mSurfaceView;
    SurfaceHolder mHolder;
    Size mPreviewSize;
    List<Size> mSupportedPreviewSizes;
    Camera mCamera;
    PreviewCallback mPreviewCallback;
    AutoFocusCallback mAutoFocusCallback;

    CameraPreview(Context context, PreviewCallback previewCallback, AutoFocusCallback autoFocusCb) {
        super(context);

        mPreviewCallback = previewCallback;
        mAutoFocusCallback = autoFocusCb;        
        mSurfaceView = new SurfaceView(context);
        addView(mSurfaceView);

        // Install a SurfaceHolder.Callback so we get notified when the
        // underlying surface is created and destroyed.
        mHolder = mSurfaceView.getHolder();
        mHolder.addCallback(this);
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

    }

    public void setCamera(Camera camera) {
        mCamera = camera;
        if (mCamera != null) {
            mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
            requestLayout();
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // We purposely disregard child measurements because act as a
        // wrapper to a SurfaceView that centers the camera preview instead
        // of stretching it.
        final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
        final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
        setMeasuredDimension(width, height);

        if (mSupportedPreviewSizes != null) {
            mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
        }
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        if (changed && getChildCount() > 0) {
            final View child = getChildAt(0);

            final int width = r - l;
            final int height = b - t;

            int previewWidth = width;
            int previewHeight = height;
            if (mPreviewSize != null) {
                previewWidth = mPreviewSize.width;
                previewHeight = mPreviewSize.height;
            }

            // Center the child SurfaceView within the parent.
            if (width * previewHeight > height * previewWidth) {
                final int scaledChildWidth = previewWidth * height / previewHeight;
                child.layout(0, 0, width, height);
            } else {
                final int scaledChildHeight = previewHeight * width / previewWidth;
                child.layout(0, 0, width,height);

            }
        }
    }

    public void surfaceCreated(SurfaceHolder holder) {

        // The Surface has been created, acquire the camera and tell it where
        // to draw.
        try {
            if (mCamera != null) {
                mCamera.setPreviewDisplay(holder);
                mCamera.setDisplayOrientation(90);
            }
        } catch (IOException exception) {
            Log.e(TAG, "IOException caused by setPreviewDisplay()", exception);
        }
    }

    public void surfaceDestroyed(SurfaceHolder holder) {
        // Surface will be destroyed when we return, so stop the preview.
        if (mCamera != null) {
            mCamera.stopPreview();
        }
    }


    private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) {
        final double ASPECT_TOLERANCE = 0.1;
        double targetRatio = (double) w / h;
        if (sizes == null) return null;

        Size optimalSize = null;
        double minDiff = Double.MAX_VALUE;

        int targetHeight = h;

        // Try to find an size match aspect ratio and size
        for (Size size : sizes) {
            double ratio = (double) size.width / size.height;
            if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
            if (Math.abs(size.height - targetHeight) < minDiff) {
                optimalSize = size;
                minDiff = Math.abs(size.height - targetHeight);
            }
        }

        // Cannot find the one match the aspect ratio, ignore the requirement
        if (optimalSize == null) {
            minDiff = Double.MAX_VALUE;
            for (Size size : sizes) {
                if (Math.abs(size.height - targetHeight) < minDiff) {
                    optimalSize = size;
                    minDiff = Math.abs(size.height - targetHeight);
                }
            }
        }
        return optimalSize;
    }

    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        if (holder.getSurface() == null){
            // preview surface does not exist
            return;
        }

        // Now that the size is known, set up the camera parameters and begin
        // the preview.
        if(mCamera!=null){
            Camera.Parameters parameters = mCamera.getParameters();

            parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
            requestLayout();

            mCamera.setParameters(parameters);
            mCamera.setPreviewCallback(mPreviewCallback);
            mCamera.startPreview();
            mCamera.autoFocus(mAutoFocusCallback);
        }
    }

}   

解决方案

I met the same problem some days before, I need to show a camera preview view on top of the GoogleMap v2, the following is my solution, hope it helps you.

    // construct a camera preview layout then show it, or remove it then hide
    popCamera.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            if(cameraBar.getVisibility() == View.VISIBLE) {
                cameraBar.removeAllViews();
                cameraBar.setVisibility(View.INVISIBLE);
            }else if(cameraBar.getVisibility() == View.INVISIBLE) {
                // new camera surface view then add to preview area
                if (cameraSurfaceView == null) {
                    cameraSurfaceView = new CameraSurfaceView(getApplicationContext());
                    // === the key point ===
                    **cameraSurfaceView.setZOrderOnTop(true);**
                    LinearLayout.LayoutParams param = new LinearLayout.LayoutParams(
                            LinearLayout.LayoutParams.MATCH_PARENT,
                            LinearLayout.LayoutParams.MATCH_PARENT);
                    previewArea.addView(cameraSurfaceView, param);
                }

                cameraBar.removeAllViews();

                cameraBar.addView(previewArea);
                cameraBar.addView(snapArea);
                cameraBar.setVisibility(View.VISIBLE);
            }
        }
    });

这篇关于相机preVIEW和API的GoogleMaps查看V2之间的Andr​​oid SurfaceView冲突的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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