android textureview全屏预览,正确的宽高比

时间:2016-07-22 21:16:05

标签: java android android-camera android-camera2 android-textureview

我一直在使用camera2 api demo from google,不幸的是,示例应用程序是为了在屏幕高度的大约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商店中的许多应用程序已找到解决此问题的方法,但无法找到修复程序,任何帮助都会有很长的路要走,谢谢。

5 个答案:

答案 0 :(得分:16)

我能够通过切换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);
        }
    }

答案 1 :(得分: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());

}

答案 2 :(得分: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一样

答案 3 :(得分:0)

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

但是,如果您的屏幕尺寸不是标准尺寸(基本上是16:9或4:3),特别是一旦您减去软按钮和通知栏(假设您没有完全全屏),然后,预览填充屏幕的唯一选择是切掉一些。

您应该能够通过查看视图的宽度和高度以及所选的预览宽度和高度来修改TextureView的变换矩阵以消除失真,但这必然会将其中一部分切掉。

答案 4 :(得分: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)
            }
        }
    }

}