Android ImageView - 16:9

时间:2016-11-08 19:07:47

标签: android bitmap android-imageview aspect-ratio

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

4 个答案:

答案 0 :(得分:18)

由于API级别26.0.0中已弃用PercentFrameLayoutPercentRelativeLayout,我建议您考虑使用ConstraintLayout来保持ImageView的比率为16:9 1}}。 ConstraintLayout是构建Android平台响应式用户界面的强大工具,您可以在Build a Responsive UI with ConstraintLayout找到更多详细信息。

以下是如何将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>

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

implementation "com.android.support.constraint:constraint-layout:1.0.2"

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

Layout Editor

答案 1 :(得分:5)

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

编辑03/29/2018:我的回答可能很简单,但可能是原始答案太多了。如果您想使用Google ConstraintLayout已经提供的内容,请按this answer或向下滚动查看@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);
    }
}

然后在你的xml中

<path.to.package.CustomImageView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/img"/>

答案 2 :(得分:5)

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

  

将大小设置为比率   如果至少有一个视图尺寸设置为&#34;匹配约束&#34;您可以将视图大小设置为16:9之比。 (0dp)。要启用比率,请单击“切换纵横比约束”(图10中的标注1),然后在显示的输入中输入宽度:高度比。

     

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

     

例如,如果将两边都设置为&#34;匹配约束&#34;,请单击两次切换纵横比约束以将宽度设置为高度的比率。现在整个尺寸由视图的高度决定(可以任何方式定义),如下图所示:

     

The view is set to a 16:9 aspect with the width based on a ratio of the height.

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

支持库中有一些名为PercentFrameLayoutPercentRelativeLayout的内容。

<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>

如果您仔细查看上面的布局,您会发现有问题的ImageView(需要修复为16:9)围绕PercentFrameLayout并且在ImageView上设置了两个您之前可能没有看到过的属性:

app:layout_widthPercent="100%"
app:layout_aspectRatio="178%"

所以(1)您需要将其中一个维度(宽度或高度)定义为我们所讨论的ImageView前导维度。在这种情况下,ImageView将垂直展开,达到最大宽度(如android:layout_width="match_parent") 并且(2)您需要设置纵横比百分比(因此库的名称),在这种情况下为178%(16/9 = 1.77777777778或更简单地将1.78:1或178%)。

详细了解百分比支持库here

答案 3 :(得分:3)

以上答案对我没有用,我发现了这个并且有效:

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();
  }
}

注意:一个simbol *更改为/(阅读源代码中的注释) 这在你的/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>

然后你可以在你的布局中使用这种方式(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" />

Source