我正在设置一个Android应用,我想拍摄会员卡的照片。我想将相机视图的方向设置为纵向模式并调整预览大小。现在,我可以正确调整预览的大小,但是当我更改方向(mCamera.setDisplayOrientation(90))时,我将所有内容弄乱了,并且预览被水平拉伸。
我的XML:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".activities.CardCaptureActivity"
android:background="@color/blue">
<android.support.v7.widget.CardView
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="20dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="20dp"
android:layout_marginBottom="8dp"
android:elevation="5dp"
app:cardCornerRadius="15dp"
app:layout_constraintBottom_toTopOf="@+id/button_capture"
app:layout_constraintDimensionRatio="H,1.618:1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="spread">
<FrameLayout
android:id="@+id/camera_preview"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</android.support.v7.widget.CardView>
<Button
android:id="@+id/button_capture"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:text="Capture"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</android.support.constraint.ConstraintLayout>
CardCaptureActivity:
class CardCaptureActivity : AppCompatActivity() {
private var mCamera: Camera? = null
private var mPreview: CardCameraPreview? = null
private var captureButton: Button? = null
companion object {
var data: ByteArray? = null
}
private val mPicture = Camera.PictureCallback { bytes, camera ->
CardCaptureActivity.data = bytes
setResult(CommonStatusCodes.SUCCESS)
finish()
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_card_capture)
captureButton = findViewById(R.id.button_capture)
captureButton?.setOnClickListener {
// get an image from the camera
mCamera?.takePicture(null, null, mPicture)
}
mCamera = getCameraInstance()
mPreview = mCamera?.let {
CardCameraPreview(this, it, findViewById(R.id.camera_preview))
}
mPreview?.also {
val preview: FrameLayout = findViewById(R.id.camera_preview)
preview.addView(it)
}
}
override fun finish() {
mCamera?.stopPreview()
mCamera?.release()
mCamera = null
super.finish()
}
override fun onDestroy() {
mCamera?.stopPreview()
mCamera?.release()
mCamera = null
super.onDestroy()
}
override fun onStop() {
mCamera?.stopPreview()
super.onStop()
}
/** Check if this device has a camera */
private fun checkCameraHardware(context: Context): Boolean {
return context.packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA)
}
/** A safe way to get an instance of the Camera object. */
fun getCameraInstance(): Camera? {
return try {
Camera.open() // attempt to get a Camera instance
} catch (e: Exception) {
// Camera is not available (in use or does not exist)
null // returns null if camera is unavailable
}
}
}
CardCameraPreview:
class CardCameraPreview(context: Context, private val mCamera: Camera, private val frameLayout: FrameLayout) : SurfaceView(context), SurfaceHolder.Callback{
private val TAG = "CardCameraPreview"
private val mHolder: SurfaceHolder = holder.apply {
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
addCallback(this@CardCameraPreview)
// deprecated setting, but required on Android versions prior to 3.0
setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS)
}
override fun surfaceCreated(p0: SurfaceHolder?) {
// The Surface has been created, now tell the camera where to draw the preview.
mCamera.apply {
try {
parameters?.also {params ->
params.focusMode = Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE
parameters = params
}
setPreviewDisplay(holder)
startPreview()
} catch (e: IOException) {
Log.d(TAG, "Error setting camera preview: ${e.message}")
}
}
}
override fun surfaceDestroyed(holder: SurfaceHolder) {
// empty. Take care of releasing the Camera preview in your activity.
}
override fun surfaceChanged(holder: SurfaceHolder, format: Int, w: Int, h: Int) {
// If your preview can change or rotate, take care of those events here.
// Make sure to stop the preview before resizing or reformatting it.
if (mHolder.surface == null) {
// preview surface does not exist
return
}
// stop preview before making changes
try {
mCamera.stopPreview()
} catch (e: Exception) {
// ignore: tried to stop a non-existent preview
}
// set preview size and make any resize, rotate or
// reformatting changes here
//mCamera.setDisplayOrientation(90)
val params = mCamera.parameters
val newSize = getOptimalPreviewSize(params.supportedPreviewSizes, frameLayout.width, frameLayout.height)
if(newSize != null) {
params.setPreviewSize(newSize.width, newSize.height)
}
params.focusMode = Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE
mCamera.setDisplayOrientation(90)
mCamera.parameters = params
// start preview with new settings
mCamera.apply {
try {
setPreviewDisplay(mHolder)
startPreview()
} catch (e: Exception) {
Log.d(TAG, "Error starting camera preview: ${e.message}")
}
}
}
private fun getOptimalPreviewSize(sizes: List<Camera.Size>?, width: Int, height: Int): Camera.Size?{
if(sizes == null)
return null
val ratio = height.toDouble()/width
var optimalSize: Camera.Size? = null
var actualDiff = Double.MAX_VALUE
sizes.forEach { size ->
val actualRatio = size.height.toDouble() / size.width
if(ratio - actualRatio < actualDiff && ratio - actualRatio >= 0){
actualDiff = ratio - actualRatio
optimalSize = size
}
else if(actualRatio - ratio < actualDiff && actualRatio - ratio >= 0){
actualDiff = actualRatio - ratio
optimalSize = size
}
}
return optimalSize
}
}
我的代码的实际结果是预览的方向是正确的(纵向),但是预览是水平拉伸的(图2)。如果我删除“ mCamera.setDisplayOrientation(90)”行,则预览具有完美的尺寸(没有拉伸或类似的东西),但是预览的方向不正确(图像1)。 预期的结果是纵向模式下的预览,并且不会拉伸预览。
如果您正在查看我的xml,您会看到预览是一个很小的矩形,带有圆角,而不是整个屏幕。那就是我想要的。