如何使SurfaceView比屏幕更大?

时间:2011-05-18 20:57:22

标签: android camera zoom surfaceview

我想为相机预览有效地进行简单的数码变焦,所以我想我只需将SurfaceView的大小调整为大于屏幕。其他问题(例如3813049)似乎表明这很容易,所以我创建了下面的示例代码,我希望能让我只看到水平图像的一半(因为SurfaceView的宽度是屏幕的两倍)并且图像只占水平屏幕的一半。但是,运行它(当我的Thunderbolt上使用Android 2.2.1定位到SDK版本4时)可以在水平填充屏幕时水平查看整个图像。 SurfaceView似乎垂直行为(当我使它小于屏幕时),但Android不允许我使SurfaceView大于屏幕。

如何实现数码变焦? (不,我不能使用Camera.Parameters.setZoom;不仅Android 1.6不支持,但不同的相机支持和实现这一点不同)

public class MagnifyTestActivity extends Activity implements SurfaceHolder.Callback {
    private MagnificationView mPreview;
    private SurfaceHolder mHolder;
    private Camera mCamera = null;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mPreview = new MagnificationView(this);
        setContentView(mPreview);
        mHolder = mPreview.getHolder();
        mHolder.addCallback(this);
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    public class MagnificationView extends SurfaceView {
        public MagnificationView(Context context) {
            super(context);
        }

        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            Display display = getWindowManager().getDefaultDisplay();
            int width = display.getWidth()*2;
            int height = display.getHeight()/2;
            widthMeasureSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
            heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }
    }

    public void surfaceCreated(SurfaceHolder holder) {
        mCamera = Camera.open();
        try {
            mCamera.setPreviewDisplay(holder);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void surfaceDestroyed(SurfaceHolder holder) {
        mCamera.stopPreview();
        mCamera.release();
        mCamera = null;
    }

    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        mHolder.setFixedSize(w, h);
        mCamera.startPreview();
    }
}

更新:基于@Pulkit Sethi的响应,可以垂直拉伸/放大SurfaceView,而不是水平放大/放大。要垂直放大SurfaceView,只需将display.getHeight()/ 2替换为上面的display.getHeight()* 2即可。还要注意,在我的代码或Pulkit中,改变宽度不会产生任何水平放大。

4 个答案:

答案 0 :(得分:3)

//Activity class

public class CameraActivity extends Activity implements SurfaceListener {

    private static final String TAG = "CameraActivity";

    Camera mCamera;
    CameraPreview mPreview;
    private FrameLayout mCameraPreview;


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);

        setContentView(R.layout.activity_camera);

        mCamera = getCameraInstance();
        mPreview = new CameraPreview(this, mCamera);

        mCameraPreview = (FrameLayout) findViewById(R.id.camera_preview);
        mCameraPreview.addView(mPreview);


    }

    @Override
    protected void onPause() {
        super.onPause();

        releaseCamera();
    }

    private Camera getCameraInstance() {
        Camera camera = null;
        try {
            camera = Camera.open();
        } catch (Exception e) {

        }
        return camera;
    }

    private void releaseCamera() {
        if (null != mCamera) {
            mCamera.release();
        }

        mCamera = null;
    }

    @Override
    public void surfaceCreated() {

        //Change these mate
        int width = 1000;
        int height = 1000;
        // Set parent window params
        getWindow().setLayout(width, height);

        RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
                width, height);
        mCameraPreview.setLayoutParams(params);
        mCameraPreview.requestLayout();
    }
}

// Preview class

public class CameraPreview extends SurfaceView implements
        SurfaceHolder.Callback {

    private static final String TAG = "CameraPreview";

    Context mContext;
    Camera mCamera;
    SurfaceHolder mHolder;

    public interface SurfaceListener{
        public void surfaceCreated();
    }
    SurfaceListener listener;


    public CameraPreview(Context context, Camera camera) {
        super(context);

        mContext = context;
        listener = (SurfaceListener)mContext;
        mCamera = camera;

        mHolder = getHolder();
        mHolder.addCallback(this);

        // Required prior 3.0 HC
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {

        try {
            mCamera.setPreviewDisplay(holder);

            Parameters params = mCamera.getParameters();
            //Change parameters here
            mCamera.setParameters(params);

            mCamera.startPreview();

            listener.surfaceCreated();

        } catch (Exception e) {
            // TODO: handle exception
        }
    }

    public void surfaceDestroyed(SurfaceHolder holder) {
        // empty. Take care of releasing the Camera preview in your activity.
    }

    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        // If your preview can change or rotate, take care of those events here.
        // Make sure to stop the preview before resizing or reformatting it.

        Log.i(TAG, "Surface changed called");
        if (mHolder.getSurface() == null) {
            // preview surface does not exist
            return;
        }

        // stop preview before making changes
        try {
            mCamera.stopPreview();
        } catch (Exception e) {
            // ignore: tried to stop a non-existent preview
        }

        // set preview size and make any resize, rotate or
        // reformatting changes here
        mCamera.setDisplayOrientation(90);

        // start preview with new settings
        try {
            mCamera.setPreviewDisplay(mHolder);
            mCamera.startPreview();

        } catch (Exception e) {
            Log.d(TAG, "Error starting camera preview: " + e.getMessage());
        }
    }

}

//Layout file 
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <FrameLayout
        android:id="@+id/camera_preview"
        android:layout_width="300dp"
        android:layout_height="400dp"
        android:layout_centerHorizontal="true"
        android:paddingTop="10dp" >
    </FrameLayout>

</RelativeLayout>

答案 1 :(得分:1)

您无法使SurfaceView比屏幕更大。可以说有很多方法。

我发现你可以在SurfaceView中调整画布的大小,这样就可以进行缩放。

public class DrawingThread extends Thread {
private MagnificationView mainPanel;
private SurfaceHolder surfaceHolder;
private boolean run;

public DrawingThread(SurfaceHolder surface, MagnificationView panel){
    surfaceHolder = surface;
    mainPanel = panel;
}

public SurfaceHolder getSurfaceHolder(){
    return surfaceHolder;
}

public void setRunning (boolean run){
    this.run = run;
}

public void run(){
    Canvas c;
    while (run){
        c = null;
        try {
            c = surfaceHolder.lockCanvas(null);
            synchronized (surfaceHolder){
                mainPanel.OnDraw(c);
            }
        } finally {
            if (c != null){
                surfaceHolder.unlockCanvasAndPost(c);
            }
        }
    }
}

}

在MagnificationView类中添加一个方法:

public void OnDraw(Canvas canvas){
    if (canvas!=null){
        canvas.save();
        canvas.scale(scaleX,scaleY);      

        canvas.restore();
    }
}

DrawingThread将是您在Activity中开始的一个主题。同样在您的MagnificationView类中,覆盖OnTouchEvent以处理您自己的缩放缩放(这将修改scaleX&amp; scaleY。

希望这可以解决您的问题

答案 2 :(得分:1)

你可以做的是获取窗口并设置其高度:

getWindow()。setLayout(1000,1000);

这会使您的窗口大于制作根视图的屏幕,因此您的表面视图可能包含在大于屏幕的Framelayout内。

这对我有用,请告诉我。

无论如何,上述都会奏效。你想要做的是为你的表面视图监听onSurfaceCreated事件。然后,在启动摄像机视图后,您可以计算包含预览的窗口小部件的大小,您可能希望更改容器窗口小部件的大小。

概念是你的容器小部件(可能是FrameLayout)想要比屏幕大。屏幕本身受活动限制,因此首先设置窗口大小

然后设置framelayout的大小(它总是缩小到最大窗口大小,所以相应地设置)。

在onSurfaceCreated完成后,我完成了所有这些逻辑我已经开始预览了。我通过实现一个小界面在我的活动中监听这个事件,因为我的Camera预览是一个单独的类。

处理所有API级别&gt; = 8。

答案 3 :(得分:0)

此处我的TouchSurfaceView onMeasure执行缩放:

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        int width = MeasureSpec.getSize(widthMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);
        setMeasuredDimension((int) (width * scaleFactor), (int) (height * scaleFactor));
    }

这可以根据scaleFactor正确放大和缩小。

我还没有使用相机对此进行测试,但它与MediaPlayer(表现为VideoView)一起正常运行。