比率を16:9に保つために、ビットマップをImageViewに設定する必要があります。何かアドバイスはありますか?主な解決策は、おそらくカスタムImageViewのオーバーライドメソッドonMeasureにありますが、どのようにしたらよいでしょうか。
編集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"/>
PercentFrameLayout
とPercentRelativeLayout
はAPIレベル26.0.0で廃止されたため、ConstraintLayout
を使用して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>
モジュールのconstraint-layout
ファイルにbuild.gradle
依存関係を追加することを忘れないでください
implementation "com.Android.support.constraint:constraint-layout:1.0.2"
または、XMLファイルを編集する代わりに、レイアウトエディターで直接レイアウトを編集します。
編集:GoogleはAPI 26以降のパーセントサポートライブラリを正式に非推奨にしました。できるだけ早くライブラリから離れる必要があります。
サイズを比率として設定するビューのサイズの少なくとも1つが「制約の一致」(0dp)に設定されている場合、ビューのサイズを16:9などの比率に設定できます。比率を有効にするには、[アスペクト比の制約の切り替え](図10の図の1)をクリックし、表示される入力に幅:高さの比率を入力します。
幅と高さの両方が制約に一致するように設定されている場合は、[アスペクト比制約の切り替え]をクリックして、他の比率に基づく寸法を選択できます。ビューインスペクタは、対応するエッジを実線で接続することにより、比率として設定されているものを示します。
たとえば、両側を「一致する制約」に設定する場合は、[アスペクト比の制約を切り替える]を2回クリックして、幅を高さの比率に設定します。下の図に示すように、全体のサイズはビューの高さ(任意の方法で定義できます)によって決まります。
詳細はこちら: 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%)。
パーセントサポートライブラリの詳細を読む ここ 。
上記の答えは私にはうまくいきませんでした、私はこれを見つけてうまくいきました:
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" />