将图片适应到ImageView中,保持长宽比并调整ImageView大小以适应图片尺寸?

197
如何将大小随机的图像适配到ImageView中?
当:
- 最初,ImageView的尺寸为250dp * 250dp - 图像的较大尺寸应缩放至250dp - 图像应保持其纵横比 - 缩放后的ImageView尺寸应与缩放后的图像尺寸相匹配
例如,对于100*150的图像,图像和ImageView应为166*250。 例如,对于150*100的图像,图像和ImageView应为250*166。
如果我将边界设置为:
<ImageView
    android:id="@+id/picture"
    android:layout_width="250dp"
    android:layout_height="250dp"
    android:layout_gravity="center_horizontal"
    android:layout_marginTop="20dp"
    android:adjustViewBounds="true" />

图片在ImageView中适当地适应,但ImageView的大小始终为250dp * 250dp。


你是指要将ImageView的大小更改为图像大小吗?例如,100dp x 150dp的图像将缩放ImageView到相同的尺寸?还是您想知道如何将图像缩放到ImageView边界。例如,1000dp x 875dp的图像将缩放为250dp x 250dp。您需要保持纵横比吗? - Jarno Argillander
我希望ImageView具有图像的尺寸,并且图像的最大尺寸等于250dp并保持其纵横比。例如,对于100150的图像,我希望图像和ImageView为166250。我将更新我的问题。 - jul
你想在显示活动时(仅执行一次)进行缩放/调整,还是在执行某些操作时,例如从图库/网络选择图片(多次执行但不在加载时),或两者都要执行? - Jarno Argillander
请查看我的修改后的答案,它应该完全符合您的要求 :) - Jarno Argillander
21个回答

291

可能不是对于这个具体问题的答案,但如果有人像我一样正在寻找如何将图像适应带限制大小(例如maxWidth)的ImageView并保持长宽比,然后摆脱ImageView占用的多余空间,那么最简单的解决方案是在XML中使用以下属性:

    android:scaleType="centerInside"
    android:adjustViewBounds="true"

15
如果你不希望图片在太小的情况下被放大,那么这个方法就适用。 - Janusz
如果它太小了,我该如何扩大它并保持纵横比? - Kaustubh Bhagwat
1
如果有人需要,"fitCenter" 是 scaleType 的另一个属性。它不会将图像放大,但对于任何大图像,它将适合视图框内的最大图像大小并保持其纵横比。 - yogesh prajapati
2
要将小图像放大,请改用scaleType =“centerCrop”。 - Eaweb
还有一件事情需要我处理,就是使用"android:src"而不是"android:background"来引用我的图片。 - Codingpan

147

(在澄清原问题后,答案进行了大幅修改)

经过澄清:
这个问题不能仅通过xml实现。无法同时缩放图像和ImageView,使得图像的一个维度始终为250dp,并且ImageView的尺寸与图像相同。

此代码将 ImageViewDrawable 缩放到一个正方形中,大小为250dp x 250dp,其中一个维度恰好为250dp,并保持宽高比。然后,ImageView 被调整大小以匹配缩放后的图像的尺寸。该代码用于活动中。我通过按钮点击处理程序进行了测试。

祝使用愉快。:)

private void scaleImage(ImageView view) throws NoSuchElementException  {
    // Get bitmap from the the ImageView.
    Bitmap bitmap = null;

    try {
        Drawable drawing = view.getDrawable();
        bitmap = ((BitmapDrawable) drawing).getBitmap();
    } catch (NullPointerException e) {
        throw new NoSuchElementException("No drawable on given view");
    } catch (ClassCastException e) {
        // Check bitmap is Ion drawable
        bitmap = Ion.with(view).getBitmap();
    }

    // Get current dimensions AND the desired bounding box
    int width = 0;

    try {
        width = bitmap.getWidth();
    } catch (NullPointerException e) {
        throw new NoSuchElementException("Can't find bitmap on given view/drawable");
    }

    int height = bitmap.getHeight();
    int bounding = dpToPx(250);
    Log.i("Test", "original width = " + Integer.toString(width));
    Log.i("Test", "original height = " + Integer.toString(height));
    Log.i("Test", "bounding = " + Integer.toString(bounding));

    // Determine how much to scale: the dimension requiring less scaling is
    // closer to the its side. This way the image always stays inside your
    // bounding box AND either x/y axis touches it.  
    float xScale = ((float) bounding) / width;
    float yScale = ((float) bounding) / height;
    float scale = (xScale <= yScale) ? xScale : yScale;
    Log.i("Test", "xScale = " + Float.toString(xScale));
    Log.i("Test", "yScale = " + Float.toString(yScale));
    Log.i("Test", "scale = " + Float.toString(scale));

    // Create a matrix for the scaling and add the scaling data
    Matrix matrix = new Matrix();
    matrix.postScale(scale, scale);

    // Create a new bitmap and convert it to a format understood by the ImageView 
    Bitmap scaledBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);
    width = scaledBitmap.getWidth(); // re-use
    height = scaledBitmap.getHeight(); // re-use
    BitmapDrawable result = new BitmapDrawable(scaledBitmap);
    Log.i("Test", "scaled width = " + Integer.toString(width));
    Log.i("Test", "scaled height = " + Integer.toString(height));

    // Apply the scaled bitmap
    view.setImageDrawable(result);

    // Now change ImageView's dimensions to match the scaled image
    LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) view.getLayoutParams(); 
    params.width = width;
    params.height = height;
    view.setLayoutParams(params);

    Log.i("Test", "done");
}

private int dpToPx(int dp) {
    float density = getApplicationContext().getResources().getDisplayMetrics().density;
    return Math.round((float)dp * density);
}

ImageView的xml代码:

<ImageView a:id="@+id/image_box"
    a:background="#ff0000"
    a:src="@drawable/star"
    a:layout_width="wrap_content"
    a:layout_height="wrap_content"
    a:layout_marginTop="20dp"
    a:layout_gravity="center_horizontal"/>


感谢这篇讨论提供的缩放代码:
http://www.anddev.org/resize_and_rotate_image_-_example-t621.html


更新于2012年11月7日:
根据评论建议添加了空指针检查。


1
ImageView 的大小将始终为 250*250。 - jul
2
好的。这不能仅通过 XML 实现。需要使用 Java 代码。使用 XML,您只能缩放图像或“ImageView”,而不能同时进行两者。 - Jarno Argillander
118
没想到你可以用 a: 代替 android:。 - StackOverflowed
1
大家好,有人能告诉我这行代码中的 Ion 是什么吗?代码如下:bitmap = Ion.with(view).getBitmap(); - Karthik
2
Ion是一个用于异步网络和图像加载的框架: https://github.com/koush/ion - Thomas
显示剩余4条评论

54
<ImageView android:layout_width="match_parent"
           android:layout_height="wrap_content"
           android:scaleType="centerCrop"
           android:adjustViewBounds="true"/>

26

以下代码可使位图与图像视图的大小完全匹配。获取位图图像的高度和宽度,然后利用图像视图的参数计算新的高度和宽度,以获得最佳纵横比的所需图像。

int currentBitmapWidth = bitMap.getWidth();
int currentBitmapHeight = bitMap.getHeight();

int ivWidth = imageView.getWidth();
int ivHeight = imageView.getHeight();
int newWidth = ivWidth;

newHeight = (int) Math.floor((double) currentBitmapHeight *( (double) new_width / (double) currentBitmapWidth));

Bitmap newbitMap = Bitmap.createScaledBitmap(bitMap, newWidth, newHeight, true);

imageView.setImageBitmap(newbitMap)

享受。


3
这将仅通过减少宽度的比例因子来减少原始高度。这并不能保证新高度小于ivHeight。理想情况下,您应该检查哪个比率更大(currentBitmapHeight / ivHeight,currentBitmapWidth / ivWidth),然后根据此做出进一步决策。 - Sumit Trehan
1
这实际上完美地运作,尽管您不需要ivHeight或newWidth,只需将ivWidth放入计算中即可。 - Stuart

15

尝试将android:scaleType="fitXY"添加到您的ImageView


8
如果原始图像不是正方形,这将修改其长宽比。 - jul
1
“fitXY” 几乎总是会改变图像的纵横比。OP 明确提到必须保持纵横比。 - IcyFlame

11

这一切都可以使用XML完成...其他方法看起来相当复杂。无论如何,您只需将高度设置为所需的dp,然后将宽度设置为wrap content或相反。使用scaleType fitCenter调整图像的大小。

<ImageView
    android:layout_height="200dp"
    android:layout_width="wrap_content"
    android:scaleType="fitCenter"
    android:adjustViewBounds="true"
    android:src="@mipmap/ic_launcher"
    android:layout_below="@+id/title"
    android:layout_margin="5dip"
    android:id="@+id/imageView1">

10

在大多数情况下,最好的解决方案是

这里有一个例子:

<ImageView android:id="@+id/avatar"
           android:layout_width="match_parent"
           android:layout_height="match_parent"
           android:scaleType="fitXY"/>

1
不要依赖已弃用的API(fill_parent) - fdermishin
1
这个回答如何解决原帖的问题?这不会保持宽高比。 - Alex

8

在搜索了一整天后,我认为这是最简单的解决方案:

imageView.getLayoutParams().width = 250;
imageView.getLayoutParams().height = 250;
imageView.setAdjustViewBounds(true);

2
谢谢您的好答案,但我认为最好在XML中添加adjustViewBounds - user1922137

7

编辑Jarno Argillanders的回答:

如何使图像适应您的宽度和高度:

1)初始化ImageView并设置图像:

iv = (ImageView) findViewById(R.id.iv_image);
iv.setImageBitmap(image);

2) 现在进行调整大小:

scaleImage(iv);

编辑了 scaleImage 方法:(您可以替换期望的边界值

private void scaleImage(ImageView view) {
    Drawable drawing = view.getDrawable();
    if (drawing == null) {
        return;
    }
    Bitmap bitmap = ((BitmapDrawable) drawing).getBitmap();

    int width = bitmap.getWidth();
    int height = bitmap.getHeight();
    int xBounding = ((View) view.getParent()).getWidth();//EXPECTED WIDTH
    int yBounding = ((View) view.getParent()).getHeight();//EXPECTED HEIGHT

    float xScale = ((float) xBounding) / width;
    float yScale = ((float) yBounding) / height;

    Matrix matrix = new Matrix();
    matrix.postScale(xScale, yScale);

    Bitmap scaledBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);
    width = scaledBitmap.getWidth();
    height = scaledBitmap.getHeight();
    BitmapDrawable result = new BitmapDrawable(context.getResources(), scaledBitmap);

    view.setImageDrawable(result);

    LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) view.getLayoutParams(); 
    params.width = width;
    params.height = height;
    view.setLayoutParams(params);
}

还有 .xml:

<ImageView
    android:id="@+id/iv_image"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center_horizontal" />

我认为这个转换应该是: LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) view.getLayoutParams(); 因为MarginLayoutParams继承自ViewGroup.LayoutParams。 - Jay M

6

如果对您不起作用,请将android:background替换为android:src

android:src将起到主要的作用

    <ImageView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:adjustViewBounds="true"
    android:scaleType="fitCenter"
    android:src="@drawable/bg_hc" />

它像魔法一样正常工作。

在此输入图片描述


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