我正在使用Scala基于Android ApiDemos中com.example.android.apis.graphics.CameraPreview
中的代码实现相机预览。但是,SurfaceHolder.Callback
(surfaceCreated
,surfaceChanged
和surfaceDestroyed
)的方法似乎从未被调用过。这是代码:
class TakePictureActivity extends ActivityWithLog {
lazy val preview = findViewById(R.id.preview).asInstanceOf[CameraPreview]
override def onCreate(savedInstanceState: Bundle) {
super.onCreate(savedInstanceState)
setContentView(R.layout.take_picture)
}
override def onResume {
super.onResume()
preview.camera = Camera.open()
}
override def onPause {
super.onPause()
for (c <- Option(preview.camera)) {
c.release()
preview.camera = null
}
}
}
class CameraPreview(context: Context,
attrs: AttributeSet,
defStyle: Int)
extends ViewGroup(context, attrs, defStyle)
with SurfaceHolder.Callback
with LogTag {
def this(context: Context, attrs: AttributeSet) = this(context, attrs, 0)
def this(context: Context) = this(context, null)
private var maybeCamera: Option[Camera] = None
def camera = maybeCamera.getOrElse(null)
def camera_=(c: Camera) {
maybeCamera = Option(c)
if (maybeCamera.nonEmpty) requestLayout()
}
private var previewSize: Option[Camera#Size] = None
def optimalPreviewSize(sizes: Seq[Camera#Size],
targetWidth: Int, targetHeight: Int) = {
val targetRatio = targetWidth.asInstanceOf[Double] / targetHeight
val targetArea = targetWidth * targetHeight
def closestInArea(sizes: Seq[Camera#Size]) =
sizes.minBy(s => abs(s.width * s.height - targetArea))
sizes.filter { size =>
val r = size.width.asInstanceOf[Double] / size.height
abs(r - targetRatio) < 0.1
} match {
case Seq() => closestInArea(sizes)
case xs => closestInArea(xs)
}
}
override def onMeasure(widthMeasureSpec: Int,
heightMeasureSpec: Int) {
val w = View.resolveSize(getSuggestedMinimumWidth, widthMeasureSpec)
val h = View.resolveSize(getSuggestedMinimumHeight, heightMeasureSpec)
setMeasuredDimension(w, h)
for (c <- maybeCamera) {
val sizes = c.getParameters.getSupportedPreviewSizes.asScala
previewSize = Some(optimalPreviewSize(sizes, w, h))
}
}
override def onLayout(changed: Boolean,
l: Int, t: Int, r: Int, b: Int) {
if (changed && getChildCount > 0) {
val child = getChildAt(0)
val (w, h) = (r - l, b - t)
val (pw, ph) = previewSize match {
case Some(s) => (s.width, s.height)
case None => (w, h)
}
if (w * ph > h * pw) {
val scaledChildWidth = pw * h / ph
child.layout((w - scaledChildWidth) / 2, 0,
(w + scaledChildWidth) / 2, h)
} else {
val scaledChildHeight = ph * w / pw
child.layout(0, (h - scaledChildHeight) / 2,
w, (h - scaledChildHeight) / 2)
}
}
}
val surfaceView = new SurfaceView(context)
addView(surfaceView)
surfaceView.getHolder.addCallback(this)
def surfaceCreated(holder: SurfaceHolder) {
Log.d(TAG, "surfaceCreated")
for (c <- maybeCamera) c.setPreviewDisplay(holder)
}
def surfaceChanged(holder: SurfaceHolder,
format: Int, width: Int, height: Int) {
Log.d(TAG, "surfaceChanged")
for (camera <- maybeCamera;
preSize <- previewSize) {
val params = camera.getParameters
params.setPreviewSize(preSize.width, preSize.height)
Log.d(TAG, s"setPreviewSize: ${preSize.width}x${preSize.height}")
requestLayout()
camera.setParameters(params)
camera.startPreview()
}
}
def surfaceDestroyed(holder: SurfaceHolder) {
Log.d(TAG, "surfaceDestroyed")
for (c <- maybeCamera) c.stopPreview()
}
}
和布局:
<?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">
<CameraPreview android:id="@+id/preview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<Button android:text="Capture"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
任何人都可以帮我解决这个问题吗?谢谢!
答案 0 :(得分:1)
我自己解决了。这是CameraPreview.onLayout中的拼写错误;这些行
child.layout(0, (h - scaledChildHeight) / 2,
w, (h - scaledChildHeight) / 2)
应该改为这些
child.layout(0, (h - scaledChildHeight) / 2,
w, (h + scaledChildHeight) / 2)
原因是当表面没有正确定位在屏幕上时(即完全离开屏幕),将永远不会调用回调。很高兴知道!