web-dev-qa-db-ja.com

Android ImageView-16:9

比率を16:9に保つために、ビットマップをImageViewに設定する必要があります。何かアドバイスはありますか?主な解決策は、おそらくカスタムImageViewのオーバーライドメソッドonMeasureにありますが、どのようにしたらよいでしょうか。

10
user997777

編集01/03/2019:この間ずっと、@ EugeneBrusovが以下に紹介したConstraintLayoutを使用することを強くお勧めします。個人的にはonMeasureをオーバーライドしてMathを実行するイメージビューを使用することはありません。

EDIT 03/29/2018:以下の私の答えは単純かもしれませんが、生の答えが多すぎるかもしれません。 GoogleのConstraintLayoutによってすでに提供されているものを利用したい場合は、 この回答 に従うか、下にスクロールして@EugeneBrusovの回答を参照してください。

古い答え:

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"/>
8
Saehun Sean Oh

PercentFrameLayoutPercentRelativeLayoutはAPIレベル26.0.0で廃止されたため、ConstraintLayoutを使用してImageViewConstraintLayoutは、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>

モジュールのconstraint-layoutファイルにbuild.gradle依存関係を追加することを忘れないでください

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

または、XMLファイルを編集する代わりに、レイアウトエディターで直接レイアウトを編集します。

Layout Editor

27
Eugene Brusov

編集:GoogleはAPI 26以降のパーセントサポートライブラリを正式に非推奨にしました。できるだけ早くライブラリから離れる必要があります。

サイズを比率として設定するビューのサイズの少なくとも1つが「制約の一致」(0dp)に設定されている場合、ビューのサイズを16:9などの比率に設定できます。比率を有効にするには、[アスペクト比の制約の切り替え](図10の図の1)をクリックし、表示される入力に幅:高さの比率を入力します。

幅と高さの両方が制約に一致するように設定されている場合は、[アスペクト比制約の切り替え]をクリックして、他の比率に基づく寸法を選択できます。ビューインスペクタは、対応するエッジを実線で接続することにより、比率として設定されているものを示します。

たとえば、両側を「一致する制約」に設定する場合は、[アスペクト比の制約を切り替える]を2回クリックして、幅を高さの比率に設定します。下の図に示すように、全体のサイズはビューの高さ(任意の方法で定義できます)によって決まります。

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


サポートライブラリには、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>

上記のレイアウトを詳しく見ると、問題のImageView(16:9に修正する必要があります)がPercentFrameLayoutにラップされており、2つの属性があることがわかります。これまでに見たことのないImageViewに設定します。

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

したがって、(1)問題のImageViewリーディングディメンションになるように、ディメンション(幅または高さ)の1つを定義する必要があります。この場合、ImageViewは垂直方向に拡大し、最大幅になります(Android:layout_width="match_parent"など)。(2)アスペクト比をパーセンテージで設定する必要があります(したがって、ライブラリの名前)。この場合は178%(16/9 = 1.77777777778以上、単純に1.78:1または178%)。

パーセントサポートライブラリの詳細を読む ここ

5
anthonymonori

上記の答えは私にはうまくいきませんでした、私はこれを見つけてうまくいきました:

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

注:1つの記号*/に変更されます(ソースのコメントを読んでください)そしてこれはあなたの/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" />

ソース

4
Borja