15

我一直在使用来自谷歌的 camera2 api 演示,不幸的是,示例应用程序被构建为在屏幕高度的大约 70% 处显示纹理视图预览,环顾四周后,我能够确定这是由 AutoFitTextureView 覆盖引起的onMeasure()方法如下图:

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    int width = MeasureSpec.getSize(widthMeasureSpec);
    int height = MeasureSpec.getSize(heightMeasureSpec);
    if (0 == mRatioWidth || 0 == mRatioHeight) {
        setMeasuredDimension(width, height);
    } else {
        if (width < height * mRatioWidth / mRatioHeight) {
            setMeasuredDimension(width, width * mRatioHeight / mRatioWidth);
        } else {
            setMeasuredDimension(height * mRatioWidth / mRatioHeight, height);
        }
    }
}

我试图通过在 中设置正确的高度和宽度来纠正这个setMeasuredDimension(width, height);问题,这解决了高度问题并从纹理视图给了我一个全屏预览,但是纵横比在每台设备上都完全被破坏和扭曲,什么是标准的修复方法这个?我看到 Play 商店中的许多应用程序都找到了解决此问题的方法,但无法找到修复程序,任何帮助都会有很大帮助,谢谢。

4

5 回答 5

26

我可以通过切换 setMeasuredDimension(); 来解决这个问题。

    int width = MeasureSpec.getSize(widthMeasureSpec);
    int height = MeasureSpec.getSize(heightMeasureSpec);
    if (0 == mRatioWidth || 0 == mRatioHeight) {
        setMeasuredDimension(width, height);
    } else {
        if (width < height * mRatioWidth / mRatioHeight) {
            setMeasuredDimension(height * mRatioWidth / mRatioHeight, height);
        } else {
            setMeasuredDimension(width, width * mRatioHeight / mRatioWidth);
        }
    }
于 2016-07-25T04:28:49.210 回答
2

下面是我们用来测量支持 4:3、16:9 和 1:1 预览尺寸的预览的代码。高度是缩放的,因为应用程序是纵向的,它不会旋转到横向。

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    int width = MeasureSpec.getSize(widthMeasureSpec);
    int height = MeasureSpec.getSize(heightMeasureSpec);

    Log.d(TAG, "[onMeasure] Before transforming: " + width + "x" + height);

    int rotation = ((Activity) getContext()).getWindowManager().getDefaultDisplay().getRotation();
    boolean isInHorizontal = Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation;

    int newWidth;
    int newHeight;

    Log.d(TAG, "[onMeasure] Get measured dimensions: " + getMeasuredWidth() + "x" + getMeasuredHeight());

    if (isInHorizontal) {
        newHeight = getMeasuredHeight();
        if (mAspectRatioOneOne) newWidth = getMeasuredHeight();
        else newWidth = (int) (newHeight * mAspectRatio);
    } else {
        newWidth = getMeasuredWidth();
        if (mAspectRatioOneOne) newHeight = getMeasuredWidth();
        else newHeight = (int) (newWidth * mAspectRatio);
    }

    setMeasuredDimension(newWidth, newHeight);
    Log.d(TAG, "[onMeasure] After transforming: " + getMeasuredWidth() + "x" + getMeasuredHeight());

}
于 2016-07-28T07:44:55.780 回答
1

我在使用 Camera2 实现时遇到了类似的问题。我使用 TextureView 的 AutoFitTextureView 实现作为相机的预览,并希望调整到正确的比例。我的问题来自方法的不同实现并传播到 onSurfaceTextureSizeChanged。[1]com.google.android.cameraview.CameraView#onMeasure(..) -> [2]com.google.android.cameraview.AutoFitTextureView#onMeasure(..) -> [3]onSurfaceTextureSizeChanged(..)

if [1] 与 [2]不同的问题。我在 [1] 中替换:

if (height < width * ratio.getY() / ratio.getX()) {

if (!(height < width * ratio.getY() / ratio.getX())) {

因为 [2] 如果基于宽度而不是高度

 if (width < height * mRatioWidth / mRatioHeight) {

验证方法 onMeasure(..) 是否正确实现。

或者你可以像 Edmund Rojas 那样做 - 上面

于 2019-09-10T13:32:48.860 回答
0

布局中的 AutoFitTextureView 应该使用 wrap_content

    <AutoFitTextureView
        android:id="@+id/texture"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

/**
 * A [TextureView] that can be adjusted to a specified aspect ratio.
 */
class AutoFitTextureView : TextureView {

    constructor(context: Context) : this(context, null)
    constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
    constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0) : super(context, attrs, defStyle)

    private var ratioWidth = 0
    private var ratioHeight = 0

    /**
     * Sets the aspect ratio for this view. The size of the view will be measured based on the ratio
     * calculated from the parameters. Note that the actual sizes of parameters don't matter, that
     * is, calling setAspectRatio(2, 3) and setAspectRatio(4, 6) make the same result.
     *
     * @param width  Relative horizontal size
     * @param height Relative vertical size
     */
    fun setAspectRatio(width: Int, height: Int) {
        require(!(width < 0 || height < 0)) { "Size cannot be negative." }
        ratioWidth = width
        ratioHeight = height
        requestLayout()
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        val width = MeasureSpec.getSize(widthMeasureSpec)
        val height = MeasureSpec.getSize(heightMeasureSpec)
        if (ratioWidth == 0 || ratioHeight == 0) {
            setMeasuredDimension(width, height)
        } else {
            if (width < height * ratioWidth / ratioHeight) {
                setMeasuredDimension(width, width * ratioHeight / ratioWidth)
            } else {
                setMeasuredDimension(height * ratioWidth / ratioHeight, height)
            }
        }
    }

}
于 2020-04-27T12:17:44.677 回答
0

如果您想要全屏、不失真的预览,则必须为相机选择与屏幕纵横比相匹配的预览分辨率。

但是,如果您的屏幕尺寸不是标准尺寸(基本上是 16:9 或 4:3),尤其是当您减去软按钮和通知栏后(假设您不是完全全屏),那么唯一的让预览充满屏幕的选项是切断其中的一部分。

您应该能够通过查看视图的宽度和高度以及选定的预览宽度和高度来修改 TextureView 的变换矩阵以消除失真,但这必然会减少一些失真。

于 2016-07-25T00:58:04.137 回答