84

经常被问到,从不回答(至少不是以可重复的方式)。

我有一个图像视图,其图像小于视图。我想将图像缩放到屏幕的宽度并调整 ImageView 的高度以反映图像的比例正确高度。

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

这会导致图像以原始尺寸为中心(小于屏幕宽度),边距位于侧面。不好。

所以我加了

android:adjustViewBounds="true" 

一样的效果,不好。我添加了

android:scaleType="centerInside"

一样的效果,不好。我centerInside改为fitCenter. 一样的效果,不好。我centerInside改为centerCrop.

android:scaleType="centerCrop"

现在,最后,图像被缩放到屏幕的宽度 - 但在顶部和底部被裁剪!所以我centerCrop改为fitXY.

android:scaleType="fitXY"

现在图像被缩放到屏幕的宽度,但没有在 y 轴上缩放,导致图像失真

删除android:adjustViewBounds="true"没有效果。正如其他地方所建议的那样,添加一个android:layout_gravity再次没有效果。

我尝试了其他组合 - 无济于事。所以,请问有谁知道:

如何设置 ImageView 的 XML 以填充屏幕宽度、缩放较小的图像以填充整个视图、以纵横比显示图像而不失真或裁剪?

编辑:我还尝试设置任意数字高度。这仅对设置有影响centerCrop。它将根据视图高度垂直扭曲图像。

4

8 回答 8

113

我通过创建一个包含在布局文件中的 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>
于 2013-07-02T11:24:44.443 回答
39

我遇到了和你一样的问题。在尝试不同的变化 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" />
于 2015-03-07T15:49:18.243 回答
24

XML 布局标准中没有可行的解决方案。

对动态图像大小做出反应的唯一可靠方法是LayoutParams在代码中使用。

令人失望。

于 2012-12-24T14:37:34.870 回答
9
  android:scaleType="fitCenter"

计算将保持原始 src 纵横比的比例,但也将确保 src 完全适合 dst。至少一个轴(X 或 Y)将完全适合。结果以 dst 为中心。

编辑:

这里的问题layout_height="wrap_content"是不是“允许”图像扩展。您必须为它设置一个大小,以便进行更改

  android:layout_height="wrap_content"

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

编辑2:

工作正常:

<ImageView
    android:id="@+id/imageView1"
    android:layout_width="match_parent"
    android:layout_height="300dp"
    android:scaleType="fitCenter"
    android:src="@drawable/img715945m" />
于 2012-12-21T15:30:54.697 回答
8

这是对 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" />
于 2014-07-29T06:49:50.737 回答
3

我遇到了同样的问题,但高度固定,缩放宽度保持图像的原始纵横比。我通过加权线性布局解决了它。希望您可以根据需要对其进行修改。

<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>
于 2014-05-11T02:26:18.940 回答
1

Kotlin 版本的 Mark Martinsson 的回答

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)
    }
}
于 2018-03-07T15:11:37.513 回答
0

Mark Matinsson 解决方案的又一补充。我发现我的一些图像比其他图像放大了。所以我修改了这个类,使图像按最大因子缩放。如果图像太小而无法以最大宽度缩放而不会变得模糊,它将停止缩放超出最大限制。

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);
        }
    }
}
于 2015-10-16T16:12:31.417 回答