ImageView的adjustViewBounds属性不起作用。

41

我有一个ImageView,其中android:layout_width=100dpandroid:layout_height=wrap_contentandroid:adjustViewBounds=true

它的源图片大小为50 x 50像素。但是纵横比没有得到保持 - ImageView的高度为50px而不是100px(即adjustViewBounds没有生效)。如果我有一张200 x 200像素的图片就可以 - 宽和高都是100像素。以下代码会使图片的宽度为100px,高度为50px,但源图片却是正方形:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">

    <ImageView
        android:id="@+id/photo"
        android:src="@drawable/icon"
        android:layout_width="100dp"
        android:layout_height="wrap_content"
        android:scaleType="fitXY"
        android:adjustViewBounds="true" />

</LinearLayout>

通常这样做是有效的;你能提供一个精确的代码片段吗?另外,ImageView的父级是什么?也许它的父级正在强制使用某个大小,不允许ImageView调整大小。 - Roman Nurik
啊,我找到了问题,现在会提供答案。 - Roman Nurik
5个回答

69
问题在于adjustViewBounds不能增加ImageView的尺寸,超过可绘制对象的自然尺寸.它只会缩小视图以保持纵横比;如果提供的是500x500而不是50x50的图像,则应该可以运行。

如果您对实现此行为的位置感兴趣,请参见 ImageView.java的onMeasure实现

一种解决方法是实现自定义ImageView,在onMeasure中更改此行为。


你知道有没有任何库可以修复imageView的这种行为? - android developer
7
我已经创建了一个版本的ImageView,如果你使用的是match_parent/fill_parent,则可以同时缩放缩小,而原始的ImageView则不能。实际上,我发现在动态布局中进行纵横比缩放时,这个版本的ImageView更加实用。请随意复制。来源:https://gist.github.com/Nilzor/5402789 - Nilzor
5
这是一个ScalingImageView,它的作用类似于adjustViewBounds=true,并且始终基于宽度和可缩放图片固有的长宽比例来更改高度:https://github.com/triposo/barone/blob/master/src/com/triposo/barone/ScalingImageView.java - aleb
16
这种行为似乎随着 Android 4.3 发生了改变。我的视图现在会超出其自然大小。@RomanNurik,您能确认一下吗? - devisnik
@aleb 谢谢,运行良好!devisnik - 在我的S5上(4.4.2)和Galaxy Nexus(4.3)上不会增加图像的大小。也许这是设备特定的。 - tomrozb
@devisnik,你是对的。现在这种方法可以将维度扩展到超出图像大小。 - suitianshi

13

有一种更简单的方法。将你的 ImageView 设为这样:

<ImageView
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:scaleType="fitCenter"
  android:adjustViewBounds="true"/>

通过保持长宽比,这种方式使drawable在ImageView中心拉伸以适应。我们只需要计算正确的高度来使其成比例,以便我们没有任何空白空间:

private void setImageBitmap(Bitmap bitmap, ImageView imageView){
    float i = ((float)imageWidth)/((float)bitmap.getWidth());
    float imageHeight = i * (bitmap.getHeight());
    imageView.setLayoutParams(new RelativeLayout.LayoutParams(imageWidth, (int) imageHeight));
    imageView.setImageBitmap(bitmap);
}

1
只有当将图像对齐到视图中心是您想要的时候,这才是一个好的解决方案。如果您需要灵活的对齐方式,请参见Roman Nuriks的答案和我的评论。 - Nilzor

2
除了@RomanNurik的答案之外, 您还可以在这里找到可行的解决方案,可以复制粘贴代码或添加Gradle依赖。
dependencies {
    compile 'com.inthecheesefactory.thecheeselibrary:adjustable-imageview:1.0.1'
}

顺便说一下,@Nilzor提供的解决方案对我没用


对于下一个读者,该视图被称为 com.inthecheesefactory.thecheeselibrary.widget.AdjustableImageView - natinusala

0

我有一个类似的需求;在我的情况下,我想要图像是正方形的,并且希望ImageView匹配其宽高比,以便我可以使用其背景和填充来绘制边框。

我阅读了这里的答案,但我决定制作一个布局,保证其内容(应该仅为一个视图)是正方形。这样我就可以在其中使用标准的ImageView。(而且你永远不知道,我可能会稍后做其他东西成为正方形。虽然可能不会。)

如果对其他人有用,这里是代码(随意复制)。由于我只是让它适用于我的应用程序,因此可能会有错误。 :)

public class SquareLayout extends ViewGroup
{
    public SquareLayout(Context context, AttributeSet attrs, int defStyle)
    {
        super(context, attrs, defStyle);
    }

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

    public SquareLayout(Context context)
    {
        super(context);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b)
    {
        // Work out width and height, and square size.
        int width = r - l;
        int height = b - t;

        int size, xOffset, yOffset;
        if(width < height)
        {
            size = width;
            xOffset = 0;
            yOffset = (height - size) / 2;
        }
        else
        {
            size = height;
            xOffset = (width - size) / 2;
            yOffset = 0;
        }

        for(int i = 0; i < getChildCount(); i++)
        {
            View child = getChildAt(i);
            child.layout(xOffset, yOffset, size + xOffset, size + yOffset);
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        // Get width and height.
        int w = -1, h = -1;
        switch(MeasureSpec.getMode(widthMeasureSpec))
        {
        case MeasureSpec.AT_MOST:
        case MeasureSpec.EXACTLY:
            w = MeasureSpec.getSize(widthMeasureSpec);
            break;

        case MeasureSpec.UNSPECIFIED:
            break;
        }
        switch(MeasureSpec.getMode(heightMeasureSpec))
        {
        case MeasureSpec.AT_MOST:
        case MeasureSpec.EXACTLY:
            h = MeasureSpec.getSize(heightMeasureSpec);
            break;

        case MeasureSpec.UNSPECIFIED:
            break;
        }

        // If only one of width/height is unspecified, set them both the same.
        if(w == -1 && h != -1)
        {
            w = h;
        }
        else if(h == -1 && w != -1)
        {
            h = w;
        }

        // Either they're both specified or both unspecified.
        int childMeasureSpec;
        if(w == -1)
        {
            childMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
        }
        else
        {
            childMeasureSpec = MeasureSpec.makeMeasureSpec(w, MeasureSpec.EXACTLY);
        }

        // Pass through to children.
        int maxDimension = 1;
        for(int i = 0; i < getChildCount(); i++)
        {
            View child = getChildAt(i);
            child.measure(childMeasureSpec, childMeasureSpec);
            maxDimension = Math.max(maxDimension, child.getMeasuredWidth());
            maxDimension = Math.max(maxDimension, child.getMeasuredHeight());
        }

        if(w == -1)
        {
            w = maxDimension;
            h = maxDimension;
        }

        setMeasuredDimension(w, h);
    }
}

-1

这行代码将为您完成任务 android:scaleType="fitXY"


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接