使图像适合ImageView,保持宽高比,然后将ImageView调整为图像尺寸?


164

如何使随机大小的图像适合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。您需要保持宽高比吗?
2011年

我希望ImageView具有图像的尺寸,并且图像的最大尺寸等于250dp并保持其纵横比。例如,对于100 * 150的图像,我希望图像和ImageView为166 * 250。我将更新我的问题。
七月

您是否仅在显示活动(执行一次)或在活动中执行某些操作(例如从图库/网络中选择图片(执行多次但不加载))或同时执行两项时才进行缩放/调整?
2011年

请参阅我的修改后答案,该答案应完全符合您的
期望

Answers:


136

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

经过澄清:
不能仅在xml中完成。不可能同时缩放图像和图像,ImageView因此图像的一维将始终为250dp,并且图像的维ImageView数与图像相同。

此代码将a缩放 Drawable为一个ImageView250dp 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);
}

的xml代码ImageView

<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。
七月

2
好。那不能仅在xml中完成。需要Java代码。使用xml既可以缩放图像ImageView,也可以缩放,但不能同时缩放两者。
亚诺·阿吉兰德

92
没意识到您可以用以下方式替换android ::
StackOverflowed 2012年

2
Ion是异步网络以及图像加载了一个框架:github.com/koush/ion
托马斯

1
Java是一种非常丑陋的语言,因为它需要为如此简单的任务编写大量代码。
德米特里'18

245

可能无法回答这个特定问题,但是如果有人像我一样,寻找答案,如何maxWidth在保留纵横比的同时将图像以一定尺寸(例如)放入ImageView中,然后消除ImageView占用的过多空间,则最简单的解决方案是在XML中使用以下属性:

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

13
如果您不希望图像过小,则无法放大图像。
Janusz 2014年

如果尺寸太小,又如何保持纵横比,该如何放大?
Kaustubh Bhagwat

如果有人需要,“ fitCenter”是scaleType的另一个属性,它不会按比例放大图像,但是对于任何大图像,它将适合视图框内图像的最大尺寸,并保持纵横比
yogesh prajapati

要放大小图像,请使用scaleType =“ centerCrop”。
Eaweb

使用此解决方案的另一件事是使用“ android:src”而不是“ android:background”来引用我的图像。
科丁潘

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

23

以下代码使位图与imageview的大小完全相同。获取位图图像的高度和宽度,然后借助imageview的参数计算新的高度和宽度。这样就可以为您提供具有最佳纵横比的图像。

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
这只会将原始高度减少与减少宽度相同的因子。这不会保证newHeight <ivHeight。理想情况下,您应该检查哪个比例更大(currentBitmapHeight / ivHeight,currentBitmapWidth / ivWidth),然后在此基础上做出进一步的决定。
Sumit Trehan

1
尽管您不需要ivHeight或newWidth,但这实际上可以完美地工作,只需将ivWidth放入计算中即可。
斯图尔特(Stuart)

14

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


5
如果原始图像未平方,这将修改纵横比。
2013年

1
fitXY几乎总是会改变图像的纵横比。OP明确提到必须保持纵横比。
IcyFlame

7

经过一天的搜索,我认为这是最简单的解决方案:

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

2
感谢您的答复,但是我认为最好添加adjustViewBounds到XML

7

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

这是一个例子:

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

1
不要依赖已弃用的API(fill_parent)
fdermishin

这如何回答OP的问题。这将无法保持上升比率
Alex

6

所有这些都可以使用XML完成...其他方法似乎非常复杂。无论如何,您只需将高度设置为dp中所需的高度,然后设置宽度以包装内容,反之亦然。使用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">


4

编辑过的Jarno Argillanders答案:

如何根据您的宽度和高度调整图像:

1)初始化ImageView并设置Image:

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

2)现在调整大小:

scaleImage(iv);

编辑scaleImage方法:(您可以替换EXPECTED边界值

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。
杰·雅各布斯

3

对于我的情况,做到了这一点。

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

2

如果对您不起作用,则将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" />

像魅力一样运转良好

在此处输入图片说明


1

我需要有一个ImageView和一个Bitmap,所以Bitmap被缩放为ImageView的大小,并且ImageView的大小与缩放后的Bitmap相同:)。

我一直在浏览这篇文章中的操作方法,最后完成了我想要的操作,但是这里没有介绍。

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/acpt_frag_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/imageBackground"
android:orientation="vertical">

<ImageView
    android:id="@+id/acpt_image"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:adjustViewBounds="true"
    android:layout_margin="@dimen/document_editor_image_margin"
    android:background="@color/imageBackground"
    android:elevation="@dimen/document_image_elevation" />

然后在onCreateView方法中

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

    View view = inflater.inflate(R.layout.fragment_scanner_acpt, null);

    progress = view.findViewById(R.id.progress);

    imageView = view.findViewById(R.id.acpt_image);
    imageView.setImageBitmap( bitmap );

    imageView.getViewTreeObserver().addOnGlobalLayoutListener(()->
        layoutImageView()
    );

    return view;
}

然后是layoutImageView()代码

private void layoutImageView(){

    float[] matrixv = new float[ 9 ];

    imageView.getImageMatrix().getValues(matrixv);

    int w = (int) ( matrixv[Matrix.MSCALE_X] * bitmap.getWidth() );
    int h = (int) ( matrixv[Matrix.MSCALE_Y] * bitmap.getHeight() );

    imageView.setMaxHeight(h);
    imageView.setMaxWidth(w);

}

结果是,图像可以完美地放入内部,保持宽高比,并且当位图位于内部时,ImageView中没有多余的像素。

结果

将wrap_content和adjustViewBounds设置为true对ImageView很重要,然后setMaxWidth和setMaxHeight将起作用,这是在ImageView的源代码中编写的,

/*An optional argument to supply a maximum height for this view. Only valid if
 * {@link #setAdjustViewBounds(boolean)} has been set to true. To set an image to be a
 * maximum of 100 x 100 while preserving the original aspect ratio, do the following: 1) set
 * adjustViewBounds to true 2) set maxWidth and maxHeight to 100 3) set the height and width
 * layout params to WRAP_CONTENT. */

0

我需要使用Picasso在约束布局中完成此操作,因此我合并了上述一些答案并提出了此解决方案(我已经知道要加载的图像的长宽比,因此很有用):

在setContentView(...)之后的某个地方调用了我的活动代码

protected void setBoxshotBackgroundImage() {
    ImageView backgroundImageView = (ImageView) findViewById(R.id.background_image_view);

    if(backgroundImageView != null) {
        DisplayMetrics displayMetrics = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
        int width = displayMetrics.widthPixels;
        int height = (int) Math.round(width * ImageLoader.BOXART_HEIGHT_ASPECT_RATIO);

        // we adjust the height of this element, as the width is already pinned to the parent in xml
        backgroundImageView.getLayoutParams().height = height;

        // implement your Picasso loading code here
    } else {
        // fallback if no element in layout...
    }
}

在我的XML中

<?xml version="1.0" encoding="utf-8"?>

<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:layout_editor_absoluteY="0dp"
tools:layout_editor_absoluteX="0dp">

    <ImageView
        android:id="@+id/background_image_view"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:scaleType="fitStart"
        app:srcCompat="@color/background"
        android:adjustViewBounds="true"
        tools:layout_editor_absoluteY="0dp"
        android:layout_marginTop="0dp"
        android:layout_marginBottom="0dp"
        android:layout_marginRight="0dp"
        android:layout_marginLeft="0dp"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>

    <!-- other elements of this layout here... -->

</android.support.constraint.ConstraintLayout>

注意缺少约束Bottom_toBottomOf属性。ImageLoader是我自己的用于图像加载util方法和常量的静态类。


0

我正在使用一个非常简单的解决方案。这是我的代码:

imageView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.MATCH_PARENT));
imageView.setScaleType(ImageView.ScaleType.FIT_XY);
imageView.getLayoutParams().height = imageView.getLayoutParams().width;
imageView.setMinimumHeight(imageView.getLayoutParams().width);

我的图片被动态添加到gridview中。当您对图像视图进行这些设置时,图片可以以1:1的比例自动显示。


0

使用简单数学来调整图像大小。您可以调整大小ImageView,也可以调整可绘制图像的大小,而不要设置为ImageView。找到要设置的位图的宽度和高度,ImageView然后调用所需的方法。假设您的宽度500比高度大于调用方法

//250 is the width you want after resize bitmap
Bitmat bmp = BitmapScaler.scaleToFitWidth(bitmap, 250) ;
ImageView image = (ImageView) findViewById(R.id.picture);
image.setImageBitmap(bmp);

您可以使用此类调整位图的大小。

public class BitmapScaler{
// Scale and maintain aspect ratio given a desired width
// BitmapScaler.scaleToFitWidth(bitmap, 100);
 public static Bitmap scaleToFitWidth(Bitmap b, int width)
  {
    float factor = width / (float) b.getWidth();
    return Bitmap.createScaledBitmap(b, width, (int) (b.getHeight() * factor), true);
  }


  // Scale and maintain aspect ratio given a desired height
  // BitmapScaler.scaleToFitHeight(bitmap, 100);
  public static Bitmap scaleToFitHeight(Bitmap b, int height)
  {
    float factor = height / (float) b.getHeight();
    return Bitmap.createScaledBitmap(b, (int) (b.getWidth() * factor), height, true);
   }
 }

xml代码是

<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"
android:scaleType="fitcenter" />

0

快速回答:

<ImageView
        android:id="@+id/imageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:scaleType="center"
        android:src="@drawable/yourImage"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.