【问题标题】:Fit image into ImageView, keep aspect ratio and then resize ImageView to image dimensions?将图像放入 ImageView,保持纵横比,然后将 ImageView 调整为图像尺寸?
【发布时间】:2012-01-04 04:18:29
【问题描述】:

如何将随机大小的图像适合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。你需要保持纵横比吗?
  • 我希望 ImageView 具有图像的尺寸,并且图像的最大尺寸等于 250dp 并保持其纵横比。例如。对于 100*150 的图像,我希望图像和 ImageView 为 166*250。我会更新我的问题。
  • 您是否只想在显示活动时进行缩放/调整(只做一次)或在活动上做一些事情,比如从画廊/网络中选择图片(做很多次但不在加载时)或两者都有?
  • 查看我修改后的答案,它应该完全按照你的意愿做:)

标签: android imageview scale


【解决方案1】:

(在澄清原问题后,答案被大量修改)

澄清后:
不能仅在 xml 中完成。无法同时缩放图像和ImageView,以使图像的一维始终为 250dp,而ImageView 的尺寸与图像相同。

此代码缩放 DrawableImageView 以保持在一个 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 日更新:
按照 cmets 的建议添加了空指针检查

【讨论】:

  • ImageView 将始终为 250*250。
  • 好的。这不能仅在 xml 中完成。需要 Java 代码。使用 xml,您可以缩放图像或 ImageView,不能同时缩放。
  • 没有意识到您可以将 android: 替换为:
  • 嗨,有人能告诉我什么是 Ion in the line bitmap = Ion.with(view).getBitmap();
  • Ion 是一个用于异步网络和图像加载的框架:github.com/koush/ion
【解决方案2】:

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

【讨论】:

  • 如果原始图像不是正方形,这将修改纵横比。
  • fitXY 几乎总是会改变图像的纵横比。 OP 明确提到必须保持纵横比。
【解决方案3】:

可能不是这个特定问题的答案,但如果有人像我一样,正在寻找答案如何在 ImageView 中以有限大小(例如,maxWidth)适合图像,同时保留纵横比,然后摆脱过度ImageView 占用的空间,那么最简单的解决方法就是在 XML 中使用如下属性:

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

【讨论】:

  • 如果您不希望图像太小而放大,则此方法有效。
  • 如果它太小,我如何放大它并保持纵横比?
  • 如果有人需要,“fitCenter”是scaleType的另一个属性,它不会放大图像,但是对于任何大图像,它会适应视图框内图像的最大尺寸保持纵横比
  • 要放大小图像,请改用 scaleType="centerCrop"。
  • 我要使用此解决方案的另一件事是使用“android:src”而不是“android:background”来引用我的图像。
【解决方案4】:
<ImageView android:layout_width="match_parent"
           android:layout_height="wrap_content"
           android:scaleType="centerCrop"
           android:adjustViewBounds="true"/>

【讨论】:

    【解决方案5】:

    下面的代码使位图完美地与图像视图的大小相同。获取位图图像的高度和宽度,然后借助 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)
    

    享受吧。

    【讨论】:

    • 这只会将原始高度减少与宽度减少相同的因子。这不能保证 newHeight
    • 这实际上工作得很好,虽然你不需要 ivHeight 或 newWidth,只需将 ivWidth 放入计算中即可。
    【解决方案6】:

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

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

    【讨论】:

    • 感谢您的好回答,但我认为最好将 adjustViewBounds 添加到 XML
    【解决方案7】:

    已编辑 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。
    【解决方案8】:

    使用此代码:

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

    【讨论】:

      【解决方案9】:

      这一切都可以使用 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">
      

      【讨论】:

        【解决方案10】:

        这是为我的情况做的。

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

        【讨论】:

          【解决方案11】:

          我需要在毕加索的约束布局中完成此操作,因此我将上述一些答案整合在一起并提出了这个解决方案(我已经知道我正在加载的图像的纵横比,所以这会有所帮助) :

          在我的活动代码中调用 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>
          

          请注意缺少 constraintBottom_toBottomOf 属性。 ImageLoader 是我自己的图片加载工具方法和常量的静态类。

          【讨论】:

            【解决方案12】:

            我需要一个 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);
            
            }
            

            结果是图像完美地融入其中,保持纵横比, 并且当 Bitmap 在里面时,ImageView 没有多余的剩余像素。

            Result

            拥有 ImageView 很重要 wrap_content 和 adjustViewBounds 为真, 那么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. */
            

            【讨论】:

              【解决方案13】:

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

              这是一个例子:

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

              【讨论】:

              • 不要依赖已弃用的 API (fill_parent)
              • 这如何回答 OP 的问题。这不会保持 aspet 比率
              【解决方案14】:

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

              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);
              

              我的图片是在网格视图中动态添加的。当您对imageview进行这些设置时,图片可以自动以1:1的比例显示。

              【讨论】:

                【解决方案15】:

                使用简单数学调整图像大小。您可以调整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" />
                

                【讨论】:

                  【解决方案16】:

                  如果它不适合你,那么将 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" />
                  

                  它工作得很好,就像一个魅力

                  【讨论】:

                    【解决方案17】:

                    快速回答:

                    <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" />
                    

                    【讨论】:

                      猜你喜欢
                      • 2013-08-07
                      • 2012-02-24
                      • 2020-06-14
                      • 1970-01-01
                      • 2012-03-03
                      • 2013-06-26
                      • 2012-04-15
                      相关资源
                      最近更新 更多