Android ImageView - 16:9

use*_*777 8 android bitmap aspect-ratio android-imageview

我需要将Bitmap设置为ImageView以保持16:9的比例.你有什么建议吗?主要解决方案可能是在自定义ImageView上的覆盖方法onMeasure,但是如何?

Eug*_*sov 24

由于PercentFrameLayout并且PercentRelativeLayout在API级别26.0.0中被弃用,我建议您考虑使用ConstraintLayout以保持16:9的比例ImageView.ConstraintLayout是构建Android平台响应式UI的强大工具,您可以在此处找到更多详细信息使用ConstraintLayout构建响应式UI.

下面是如何将ImageView构建到ConstraintLayout以保持16:9比率的示例:

<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_marginEnd="0dp"
        android:layout_marginStart="0dp"
        android:layout_marginTop="0dp"
        app:srcCompat="@mipmap/ic_launcher"
        app:layout_constraintDimensionRatio="H,16:9"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>
Run Code Online (Sandbox Code Playgroud)

不要忘记将constraint-layout依赖项添加到模块的build.gradle文件中

implementation "com.android.support.constraint:constraint-layout:1.0.2"
Run Code Online (Sandbox Code Playgroud)

或者不是编辑XML文件,而是直接在布局编辑器中编辑布局:

布局编辑器


Sae*_* Oh 8

编辑01/03/2019:在所有这些时间之后,我强烈建议使用ConstraintLayout下面介绍的@Eugene Brusov。我个人永远不会使用通过覆盖onMeasure进行数学运算的图像视图。

编辑03/29/2018:我下面的回答可能很简单,但可能太多了。如果您想利用Google提供的功能ConstraintLayout,请遵循此答案或向下滚动并查看@Eugene Brusov的答案。

旧答案:

public class CustomImageView extends ImageView {

    // some other necessary things

    @Override 
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        int width = getMeasuredWidth();

        //force a 16:9 aspect ratio             
        int height = Math.round(width * .5625f);
        setMeasuredDimension(width, height);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后在您的xml中

<path.to.package.CustomImageView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/img"/>
Run Code Online (Sandbox Code Playgroud)


ant*_*ori 5

编辑:Google已经正式弃用了从API 26开始的Percent支持库,您应该尽快离开它。

将尺寸设置为比例如果将至少一个视图尺寸设置为“匹配约束”(0dp),则可以将视图尺寸设置为16:9之类的比例。要启用该比率,请单击“切换纵横比约束”(图10中的标注1),然后在出现的输入中输入width:height比率。

如果宽度和高度都设置为匹配约束,则可以单击“切换纵横比约束”以选择哪个尺寸基于另一个比例。视图检查器通过用实线连接相应的边来指示将其设置为比率。

例如,如果将双方都设置为“匹配约束”,请单击两次“切换纵横比约束”以将宽度设置为高度的比率。现在,整个大小取决于视图的高度(可以通过任何方式定义),如下图所示:

将视图设置为16:9宽高比,其宽度基于高度的比例。

此处的更多信息:https : //developer.android.com/training/constraint-layout/index.html#adjust-the-view-size


有一种叫做PercentFrameLayout并且PercentRelativeLayout在支持库。

<android.support.percent.PercentFrameLayout 
  android:layout_width="match_parent"
  android:layout_height="wrap_content">
  <ImageView
    app:layout_widthPercent="100%"
    app:layout_aspectRatio="178%"
    android:scaleType="centerCrop"
    android:src="@drawable/header_background"/>
  <!-- The rest of your layout -->
</android.support.percent.PercentRelativeLayout>
Run Code Online (Sandbox Code Playgroud)

如果仔细看一下上面的布局,您会发现有ImageView问题的(需要固定在16:9处)被包裹在a周围,PercentFrameLayout并且在上设置了两个属性ImageView,您可能以前从未看到过:

app:layout_widthPercent="100%"
app:layout_aspectRatio="178%"
Run Code Online (Sandbox Code Playgroud)

因此,(1)你需要定义一个维度(宽度或高度)是领先于我们的尺寸ImageView问题。在这种情况下,ImageView它将垂直扩展到最大宽度(例如android:layout_width="match_parent")。(2)您需要以百分比设置宽高比(因此,库的名称)为178%(16/9 = 1.77777777778或更简单地讲1.78:1或178%)。

在此处阅读有关百分比支持库的更多信息。


Bor*_*rja 5

上面的答案对我不起作用,我找到了这个并工作:

public class AspectRatioImageView extends ImageView {
  // NOTE: These must be kept in sync with the AspectRatioImageView attributes in attrs.xml.
  public static final int MEASUREMENT_WIDTH = 0;
  public static final int MEASUREMENT_HEIGHT = 1;

  private static final float DEFAULT_ASPECT_RATIO = 1f;
  private static final boolean DEFAULT_ASPECT_RATIO_ENABLED = false;
  private static final int DEFAULT_DOMINANT_MEASUREMENT = MEASUREMENT_WIDTH;

  private float aspectRatio;
  private boolean aspectRatioEnabled;
  private int dominantMeasurement;

  public AspectRatioImageView(Context context) {
    this(context, null);
  }

  public AspectRatioImageView(Context context, AttributeSet attrs) {
    super(context, attrs);

    TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AspectRatioImageView);
    aspectRatio = a.getFloat(R.styleable.AspectRatioImageView_aspectRatio, DEFAULT_ASPECT_RATIO);
    aspectRatioEnabled = a.getBoolean(R.styleable.AspectRatioImageView_aspectRatioEnabled,
        DEFAULT_ASPECT_RATIO_ENABLED);
    dominantMeasurement = a.getInt(R.styleable.AspectRatioImageView_dominantMeasurement,
        DEFAULT_DOMINANT_MEASUREMENT);
    a.recycle();
  }

  @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    if (!aspectRatioEnabled) return;

    int newWidth;
    int newHeight;
    switch (dominantMeasurement) {
      case MEASUREMENT_WIDTH:
        newWidth = getMeasuredWidth();
        newHeight = (int) (newWidth / aspectRatio);
        break;

      case MEASUREMENT_HEIGHT:
        newHeight = getMeasuredHeight();
        newWidth = (int) (newHeight * aspectRatio);
        break;

      default:
        throw new IllegalStateException("Unknown measurement with ID " + dominantMeasurement);
    }

    setMeasuredDimension(newWidth, newHeight);
  }

  /** Get the aspect ratio for this image view. */
  public float getAspectRatio() {
    return aspectRatio;
  }

  /** Set the aspect ratio for this image view. This will update the view instantly. */
  public void setAspectRatio(float aspectRatio) {
    this.aspectRatio = aspectRatio;
    if (aspectRatioEnabled) {
      requestLayout();
    }
  }

  /** Get whether or not forcing the aspect ratio is enabled. */
  public boolean getAspectRatioEnabled() {
    return aspectRatioEnabled;
  }

  /** set whether or not forcing the aspect ratio is enabled. This will re-layout the view. */
  public void setAspectRatioEnabled(boolean aspectRatioEnabled) {
    this.aspectRatioEnabled = aspectRatioEnabled;
    requestLayout();
  }

  /** Get the dominant measurement for the aspect ratio. */
  public int getDominantMeasurement() {
    return dominantMeasurement;
  }

  /**
   * Set the dominant measurement for the aspect ratio.
   *
   * @see #MEASUREMENT_WIDTH
   * @see #MEASUREMENT_HEIGHT
   */
  public void setDominantMeasurement(int dominantMeasurement) {
    if (dominantMeasurement != MEASUREMENT_HEIGHT && dominantMeasurement != MEASUREMENT_WIDTH) {
      throw new IllegalArgumentException("Invalid measurement type.");
    }
    this.dominantMeasurement = dominantMeasurement;
    requestLayout();
  }
}
Run Code Online (Sandbox Code Playgroud)

注意:一个符号*更改为/(阅读源代码中的注释)而这在您的/values/attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="AspectRatioImageView">
        <attr name="aspectRatio" format="float" />
        <attr name="aspectRatioEnabled" format="boolean" />
        <attr name="dominantMeasurement">
            <enum name="width" value="0" />
            <enum name="height" value="1" />
        </attr>
    </declare-styleable>
</resources>
Run Code Online (Sandbox Code Playgroud)

然后你可以在你的布局中使用这种方式(aspectRatio = width/height):

<com.yourpackage.ui.classes.AspectRatioImageView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:scaleType="centerCrop"
        app:aspectRatio="1.78"
        app:aspectRatioEnabled="true"
        app:dominantMeasurement="width" />
Run Code Online (Sandbox Code Playgroud)

来源