我的应用程序有一组托管FragmentActivity的标签。其中一些标签包含GoogleMaps Api v2支持MapFragment和/或MapView,另一个标签包含QR扫描仪。
我面临的问题是,如果您当前正在一个选项卡上查看SupportMapFragment或MapView,然后切换到Scanner选项卡,则SurfaceView仍会被之前的SupportMapFragment / MapView接管(当然除非Fragment /在选择“扫描仪”选项卡之前删除视图。由于使用了SurfaceView,因此在尝试通过v1合并GoogleMaps Api v2之前,这不是问题。
我不完全确定如何解决这个问题,我正在思考"清除"选择“扫描仪”选项卡并启动CameraPreview时的SurfaceView?并以某种方式使用画布实现这一目标? 但是我对SurfaceView类没有太多的了解。
附件是我的#34; CameraPreview"用于在“扫描仪”选项卡上处理Android摄像头的类。 GoogleMaps api v2类只是Google提供的基本设置,没什么特别的。
感谢您的时间和帮助。
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);
}
}
}
答案 0 :(得分:1)
根据文档的声音,您应该只能同时运行一个表面视图。
我在前面有一个类似的MapFragment和CameraPreview,发现我需要MapFragment在相机预览片段工作之前释放它的资源。
这意味着将MapFragment交换为CamreaPreviewFragment而不是仅仅将其添加到顶部。
答案 1 :(得分:0)
前几天我遇到了同样的问题,我需要在GoogleMap v2的顶部显示相机预览视图,以下是我的解决方案,希望对您有帮助。
// 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);
}
}
});