web-dev-qa-db-ja.com

Android ImageViewは、切り取りや歪みなしで、柔軟な高さで小さな画像を幅に合わせて拡大縮小します

しばしば尋ねられ、決して答えられなかった(少なくとも再現可能な方法ではない)。

私はより小さいである画像を持つ画像ビューを持っています。画像を画面の幅に合わせて拡大縮小し、ImageViewの高さを調整して、比例して正しい画像の高さを反映させます。

<ImageView
    Android:layout_width="fill_parent"
    Android:layout_height="wrap_content"
/>

これにより、画像は元のサイズ(画面幅よりも小さい)の中央に配置され、余白が横になります。ダメ。

だから私は追加しました

Android:adjustViewBounds="true" 

同じ効果、ダメ。追加した

Android:scaleType="centerInside"

同じ効果、ダメ。 centerInsidefitCenterに変更しました。同じ効果、ダメ。 centerInsidecenterCropに変更しました。

Android:scaleType="centerCrop"

さて、最後に、画像はscaled画面の幅に対応していますが、上下はcroppedです!そこで、centerCropfitXYに変更しました。

Android:scaleType="fitXY"

これで、画像は画面の幅に合わせて拡大縮小されますが、y軸でnotに拡大縮小され、distorted imageになります。

Android:adjustViewBounds="true"を削除しても効果はありません。 Android:layout_gravityを追加しても、他の場所で提案されているように、効果はありません。

私は他の組み合わせを試しました-無駄に。だから、誰もが知っていますか:

画面の幅に合わせてImageViewのXMLを設定し、ビュー全体に合わせて小さい画像を拡大縮小し、歪みやトリミングなしに画像をアスペクト比で表示するにはどうすればよいですか?

編集:私はまた、任意の数値の高さを設定しようとしました。これは、centerCrop設定でのみ効果があります。ビューの高さに応じて画像を垂直に歪ませます。

76
Mundi

XMLレイアウト標準内に実行可能なソリューションはありません。

動的な画像サイズに対応する唯一の信頼できる方法は、コードでLayoutParamsを使用することです。

がっかり。

20
Mundi

レイアウトファイルに含めるJavaクラスを作成することでこれを解決しました。

public class DynamicImageView extends ImageView {

    public DynamicImageView(final Context context, final AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
        final Drawable d = this.getDrawable();

        if (d != null) {
            // ceil not round - avoid thin vertical gaps along the left/right edges
        final int width = MeasureSpec.getSize(widthMeasureSpec);
        final int height = (int) Math.ceil(width * (float) d.getIntrinsicHeight() / d.getIntrinsicWidth());
            this.setMeasuredDimension(width, height);
        } else {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }
    }
}

次に、クラスをレイアウトファイルに追加して、これを使用します。

<RelativeLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:layout_width="fill_parent"
    Android:layout_height="fill_parent" >

    <my.package.name.DynamicImageView
        Android:layout_width="fill_parent"
        Android:layout_height="wrap_content"
        Android:scaleType="centerCrop"
        Android:src="@drawable/about_image" />
</RelativeLayout>
109
Mark Martinsson

あなたと同じ問題がありました。異なるバリエーションを30分間試した後、この方法で問題を解決しました。 柔軟な高さ、および親の幅に合わせた幅

<ImageView
            Android:id="@+id/imageview_company_logo"
            Android:layout_width="fill_parent"
            Android:layout_height="fill_parent"
            Android:adjustViewBounds="true"
            Android:scaleType="fitCenter"
            Android:src="@drawable/appicon" />
34
haydarkarrar
  Android:scaleType="fitCenter"

元のsrcアスペクト比を維持するが、srcがdst内に完全に収まるようにするスケールを計算します。少なくとも1つの軸(XまたはY)が正確に適合します。結果はdstの中央に配置されます。

編集:

ここでの問題は、layout_height="wrap_content"が画像の拡大を「許可」していないことです。その変更のために、サイズを設定する必要があります

  Android:layout_height="wrap_content"

  Android:layout_height="100dp"  // or whatever size you want it to be

edit2:

正常に動作します:

<ImageView
    Android:id="@+id/imageView1"
    Android:layout_width="match_parent"
    Android:layout_height="300dp"
    Android:scaleType="fitCenter"
    Android:src="@drawable/img715945m" />
8
Budius

これは、Mark Martinssonの優れたソリューションへの小さな追加です。

画像の幅が高さよりも大きい場合、Markのソリューションは画面の上下にスペースを残します。

以下は、最初に幅と高さを比較することでこれを修正します。画像の幅が高さ以上の場合、画面の高さと一致するように高さをスケーリングし、次にアスペクト比を維持するために幅をスケーリングします。同様に、画像の高さが幅よりも大きい場合、画面の幅に合わせて幅が拡大縮小され、アスペクト比が維持されるように高さが拡大縮小されます。

つまり、scaleType="centerCrop"の定義を適切に満たしています。

http://developer.Android.com/reference/Android/widget/ImageView.ScaleType.html

の両方の寸法(幅と高さ)またはビューの対応する寸法よりも大きい(マイナスパディング)。

package com.mypackage;

import Android.content.Context;
import Android.graphics.drawable.Drawable;
import Android.util.AttributeSet;
import Android.widget.ImageView;

public class FixedCenterCrop extends ImageView
{
    public FixedCenterCrop(final Context context, final AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec)
    {
        final Drawable d = this.getDrawable();

        if(d != null) {
            int height = MeasureSpec.getSize(heightMeasureSpec);
            int width = MeasureSpec.getSize(widthMeasureSpec);

            if(width >= height)
                height = (int) Math.ceil(width * (float) d.getIntrinsicHeight() / d.getIntrinsicWidth());
            else
                width = (int) Math.ceil(height * (float) d.getIntrinsicWidth() / d.getIntrinsicHeight());

            this.setMeasuredDimension(width, height);

        } else {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }
    }
}

このソリューションは、ポートレートモードまたはランドスケープモードで自動的に機能します。 Markのソリューションで行うように、レイアウトで参照します。例えば。:

<com.mypackage.FixedCenterCrop
    Android:id="@+id/imgLoginBackground"
    Android:src="@drawable/mybackground"
    Android:layout_width="wrap_content"
    Android:layout_height="wrap_content"
    Android:layout_centerInParent="true"
    Android:scaleType="centerCrop" />
7

私は同じ問題に遭遇しましたが、高さを固定し、幅をスケーリングして、画像の元のアスペクト比を維持しました。重み付き線形レイアウトで解決しました。必要に応じて変更できます。

<LinearLayout
    xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:layout_width="wrap_content"
    Android:layout_height="wrap_content"
    Android:orientation="horizontal">

    <ImageView
        Android:id="@+id/image"
        Android:layout_width="0px"
        Android:layout_height="180dip"
        Android:layout_weight="1.0"
        Android:adjustViewBounds="true"
        Android:scaleType="fitStart" />

</LinearLayout>
3
tbm

マーク・マーティンソンのコトリン版 answer

class DynamicImageView(context: Context, attrs: AttributeSet) : AppCompatImageView(context, attrs) {
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
    val drawable = this.drawable

    if (drawable != null) {
        //Ceil not round - avoid thin vertical gaps along the left/right edges
        val width = View.MeasureSpec.getSize(widthMeasureSpec)
        val height = Math.ceil((width * drawable.intrinsicHeight.toFloat() / drawable.intrinsicWidth).toDouble()).toInt()
        this.setMeasuredDimension(width, height)
    } else {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
    }
}
0
ngu

Mark Matinssonのソリューションへのもう1つの追加。自分の画像の中には、他の画像よりも過度に拡大されたものがあることがわかりました。そこで、画像を最大係数でスケーリングするようにクラスを変更しました。画像が小さすぎてぼやけずに最大幅で拡大縮小できない場合、最大制限を超えて拡大縮小を停止します。

public class DynamicImageView extends ImageView {

    final int MAX_SCALE_FACTOR = 2;
    public DynamicImageView(final Context context) {
        super(context);
    }

    @Override
    protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
        final Drawable d = this.getDrawable();

        if (d != null) {
            // ceil not round - avoid thin vertical gaps along the left/right edges
            int width = View.MeasureSpec.getSize(widthMeasureSpec);
            if (width > (d.getIntrinsicWidth()*MAX_SCALE_FACTOR)) width = d.getIntrinsicWidth()*MAX_SCALE_FACTOR;
            final int height = (int) Math.ceil(width * (float) d.getIntrinsicHeight() / d.getIntrinsicWidth());
            this.setMeasuredDimension(width, height);
        } else {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }
    }
}
0
azmath