为了让用户有效的获取图像和视频,必须能让他们看到相机中的影像。一个相机预览类是一个SurfaceView类,它可以显示相机中的实时影像,于是用户就可以框住并捕获图像或视频。
下面例子中的代码演示了如何创建一个基本的相机预览类,此类可以被一个viewlayout包含。此类实现了SurfaceHolder.Callback,为的是获取创建和销毁view的回调事件,这个view用来分配相机预览输入。
/** 一个基本的相机预览类 */
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder mHolder;
private Camera mCamera;
public CameraPreview(Context context, Camera camera) {
super(context);
mCamera = camera;
// 安装一个SurfaceHolder.Callback,于是当下层的界面被创建或销毁时我们可以得到通知
mHolder = getHolder();
mHolder.addCallback(this);
// 过时的设置,但是android3.0之前的版本需要。
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void surfaceCreated(SurfaceHolder holder) {
// 界面被创建了,现在告诉相机何时画 preview.
try {
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
} catch (IOException e) {
Log.d(TAG, "Error setting camera preview: " + e.getMessage());
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
// 空的。在你的activity中注意释放相机预览。
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
//如果你的预览可以改变或旋转,小心这里这些事件们。
// 保证在改变大小或改变格式之前停止预览。
if (mHolder.getSurface() == null){
// 预览界面不存在
return;
}
// 改变之前停止预览
try {
mCamera.stopPreview();
} catch (Exception e){
// ignore: tried to stop a non-existent preview
}
// 设置预览尺寸并且执行所有大小改变,旋转或格式改变等。
// 开始使用新的设置预览。
try {
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e){
Log.d(TAG, "Error starting camera preview: " + e.getMessage());
}
}
}
如果你想为你的相机预览设置一个尺寸,就应在surfaceChanged()方法中进行。当设置预览尺寸时,你必须使用getSupportedPreviewSizes()来获取正确的尺寸值。不能使用setPreviewSize()设置任意的尺寸值。
将预览view放到layout中
一个相机预览类,比如前面例子中所示的,必须与其它用户界面控件一起放到layout中来获取图像或视频。本节向你演示如何为预览建立一个基本的layout和activity。
下面的layout代码提供了一个十分基础的view,这个view可以显示一个相机预览.在此例子中,FrameLayout元素是相机预览类的容器.使用layout类型是为了另外的图像信息或控制控件可以覆盖在预览图像之上显示.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<FrameLayout
android:id="@+id/camera_preview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"
/>
<Button
android:id="@+id/button_capture"
android:text="Capture"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
/>
</LinearLayout>
在多数设备上,相机预览图像的方向是横的.上面的layout例子中指定了横向的layout.为了简单地显示相机预览,你应该在你的manifest中指定你的应用的activity的方向也为横向.
<activity android:name=".CameraActivity"
android:label="@string/app_name"
android:screenOrientation="landscape">
<!-- configure this activity to use landscape orientation -->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
注:相机预览不是必须为横向的.从Android2.2 (API Level8)开始,你可以使用setDisplayOrientation()方法来设置预览图像的旋转.为了改变预览方向以与当前设备的方向相同,在你的预览类的surfaceChanged()方法中,先调用Camera.stopPreview()停止预览,再改变方向,然后使用Camera.startPreview()重新启动预览.
在你用于相机view的activity中,添加你的预览类到上面例子中的FrameLayout元素中.你的相机activity必须在其paused或关闭时确保释放相机对象.下面的例子演示了如何修改一个相机activity来附加一个预览类.
public class CameraActivity extends Activity {
private Camera mCamera;
private CameraPreview mPreview;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Create an instance of Camera
mCamera = getCameraInstance();
// Create our Preview view and set it as the content of our activity.
mPreview = new CameraPreview(this, mCamera);
FrameLayout preview = (FrameLayout) findViewById(id.camera_preview);
preview.addView(mPreview);
}
}
注:此例中的getCameraInstance()方法引用自"使用相机"一节的同名方法