Android ImageView缩小图像到宽度,灵活高度,无裁剪或失真

Mun*_*ndi 77 android imageview image-scaling

经常被问到,从来没有回答过(至少不是以可重复的方式).

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

<ImageView
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
/>
Run Code Online (Sandbox Code Playgroud)

这导致图像以其原始尺寸(小于屏幕宽度)为中心,边缘为边缘.不好.

所以我补充道

android:adjustViewBounds="true" 
Run Code Online (Sandbox Code Playgroud)

同样的效果,没有好处.我补充道

android:scaleType="centerInside"
Run Code Online (Sandbox Code Playgroud)

同样的效果,没有好处.我换centerInsidefitCenter.同样的效果,没有好处.我换centerInsidecenterCrop.

android:scaleType="centerCrop"
Run Code Online (Sandbox Code Playgroud)

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

android:scaleType="fitXY"
Run Code Online (Sandbox Code Playgroud)

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

删除android:adjustViewBounds="true"无效.android:layout_gravity如其他地方所建议的,添加一个也没有效果.

我尝试过其他组合 - 无济于事.所以,请有人知道:

如何设置ImageView的XML来填充屏幕的宽度,缩放较小的图像以填充整个视图,显示具有宽高比的图像而不会失真或裁剪?

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

Mar*_*son 110

我通过创建一个包含在layout-file中的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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,您通过将您的类添加到布局文件中来使用它:

<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>
Run Code Online (Sandbox Code Playgroud)

  • +1伟大的解决方案,也适用于Nexus 7.最好的部分是,它也可以在Eclipse的布局编辑器中正常工作. (4认同)

小智 34

我和你的问题一样.在尝试不同变化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" />
Run Code Online (Sandbox Code Playgroud)

  • 这里的关键是使用adjustViewBounds (4认同)

Mun*_*ndi 21

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

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

令人失望.


Bud*_*ius 8

  android:scaleType="fitCenter"
Run Code Online (Sandbox Code Playgroud)

计算将保持原始src宽高比的比例,但也将确保src完全适合dst.至少一个轴(X或Y)将完全适合.结果集中在dst内.

编辑:

这里的问题layout_height="wrap_content"是不是"允许"图像扩展.对于该更改,您必须为其设置大小

  android:layout_height="wrap_content"
Run Code Online (Sandbox Code Playgroud)

  android:layout_height="100dp"  // or whatever size you want it to be
Run Code Online (Sandbox Code Playgroud)

EDIT2:

工作良好:

<ImageView
    android:id="@+id/imageView1"
    android:layout_width="match_parent"
    android:layout_height="300dp"
    android:scaleType="fitCenter"
    android:src="@drawable/img715945m" />
Run Code Online (Sandbox Code Playgroud)

  • 这导致图像的第一个版本:居中,不水平扩展,两边都有边距。不好。 (2认同)
  • 这不起作用。它会生成具有精确高度的图像,但不会水平扩展。不好。另请参阅我在问题中的编辑。 (2认同)
  • 不好.我不知道身高 - 它是动态的.这将导致不可预测的扭曲.我的问题中的编辑已经涵盖了这一点.对不起 - 但谢谢你的努力!对谷歌感到羞耻! (2认同)

Mic*_*off 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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

此解决方案自动以纵向或横向模式运行.您可以像在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" />
Run Code Online (Sandbox Code Playgroud)