缩放图像以填充ImageView宽度并保持纵横比

我有一个GridViewGridView的数据是来自服务器的请求。

下面是GridView中的项布局:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/analysis_micon_bg"
android:gravity="center_horizontal"
android:orientation="vertical"
android:paddingBottom="@dimen/half_activity_vertical_margin"
android:paddingLeft="@dimen/half_activity_horizontal_margin"
android:paddingRight="@dimen/half_activity_horizontal_margin"
android:paddingTop="@dimen/half_activity_vertical_margin" >


<ImageView
android:id="@+id/ranking_prod_pic"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:contentDescription="@string/app_name"
android:scaleType="centerCrop" />


<TextView
android:id="@+id/ranking_rank_num"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />


<TextView
android:id="@+id/ranking_prod_num"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />


<TextView
android:id="@+id/ranking_prod_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>

我从服务器请求数据,获取图像url并将图像加载到Bitmap

public static Bitmap loadBitmapFromInputStream(InputStream is) {
return BitmapFactory.decodeStream(is);
}


public static Bitmap loadBitmapFromHttpUrl(String url) {
try {
return loadBitmapFromInputStream((InputStream) (new URL(url).getContent()));
} catch (Exception e) {
Log.e(TAG, e.getMessage());
return null;
}
}

适配器中有getView(int position, View convertView, ViewGroup parent)方法的代码

Bitmap bitmap = BitmapUtil.loadBitmapFromHttpUrl(product.getHttpUrl());
prodImg.setImageBitmap(bitmap);

图像大小为210*210。我在Nexus 4上运行我的应用程序。图像确实填充了ImageView的宽度,但是ImageView的高度没有缩放。ImageView不显示整个图像。

我怎么解决这个问题?

302028 次浏览

你可以尝试通过手动加载图像来做你正在做的事情,但我非常非常强烈建议看一看通用图像加载器

我最近把它整合到我的项目中,我不得不说它太棒了。这些都是异步的,调整大小,缓存图像。它真的很容易集成和设置。在5分钟内你就可以让它按你想要的做。

示例代码:

//ImageLoader config
DisplayImageOptions displayimageOptions = new DisplayImageOptions.Builder().showStubImage(R.drawable.downloadplaceholder).cacheInMemory().cacheOnDisc().showImageOnFail(R.drawable.loading).build();


ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getApplicationContext()).
defaultDisplayImageOptions(displayimageOptions).memoryCache(new WeakMemoryCache()).discCache(new UnlimitedDiscCache(cacheDir)).build();


if (ImageLoader.getInstance().isInited()) {
ImageLoader.getInstance().destroy();
}
ImageLoader.getInstance().init(config);


imageLoadingListener = new ImageLoadingListener() {
@Override
public void onLoadingStarted(String s, View view) {


}


@Override
public void onLoadingFailed(String s, View view, FailReason failReason) {
ImageView imageView = (ImageView) view;
imageView.setImageResource(R.drawable.android);
Log.i("Failed to Load " + s, failReason.toString());
}


@Override
public void onLoadingComplete(String s, View view, Bitmap bitmap) {


}


@Override
public void onLoadingCancelled(String s, View view) {


}
};


//Imageloader usage
ImageView imageView = new ImageView(getApplicationContext());
if (orientation == 1) {
imageView.setLayoutParams(new LinearLayout.LayoutParams(width / 6, width / 6));
} else {
imageView.setLayoutParams(new LinearLayout.LayoutParams(height / 6, height / 6));
}
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageLoader.displayImage(SERVER_HOSTNAME + "demos" + demo.getPathRoot() + demo.getRootName() + ".png", imageView, imageLoadingListener);

这可以延迟加载图像,使它们正确地适应imageView的大小,在加载时显示占位符图像,并在加载失败时显示默认图标并缓存资源。

我还应该补充一下,当前的配置保持了图像的纵横比,因此适用于你最初的问题

我曾经遇到过类似的问题。我通过制作一个自定义ImageView解决了这个问题。

public class CustomImageView extends ImageView

然后重写imageview的onMeasure方法。我相信我做过这样的事情:

    @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
try {
Drawable drawable = getDrawable();


if (drawable == null) {
setMeasuredDimension(0, 0);
} else {
float imageSideRatio = (float)drawable.getIntrinsicWidth() / (float)drawable.getIntrinsicHeight();
float viewSideRatio = (float)MeasureSpec.getSize(widthMeasureSpec) / (float)MeasureSpec.getSize(heightMeasureSpec);
if (imageSideRatio >= viewSideRatio) {
// Image is wider than the display (ratio)
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = (int)(width / imageSideRatio);
setMeasuredDimension(width, height);
} else {
// Image is taller than the display (ratio)
int height = MeasureSpec.getSize(heightMeasureSpec);
int width = (int)(height * imageSideRatio);
setMeasuredDimension(width, height);
}
}
} catch (Exception e) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}

这将拉伸图像以适应屏幕,同时保持纵横比。

我喜欢arnefm的回答,但他犯了一个小错误(见评论),我会尽力纠正:

import android.content.Context;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.ImageView;


/**
* ImageView that keeps aspect ratio when scaled
*/
public class ScaleImageView extends ImageView {


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


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


public ScaleImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}


@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
try {
Drawable drawable = getDrawable();
if (drawable == null) {
setMeasuredDimension(0, 0);
} else {
int measuredWidth = MeasureSpec.getSize(widthMeasureSpec);
int measuredHeight = MeasureSpec.getSize(heightMeasureSpec);
if (measuredHeight == 0 && measuredWidth == 0) { //Height and width set to wrap_content
setMeasuredDimension(measuredWidth, measuredHeight);
} else if (measuredHeight == 0) { //Height set to wrap_content
int width = measuredWidth;
int height = width *  drawable.getIntrinsicHeight() / drawable.getIntrinsicWidth();
setMeasuredDimension(width, height);
} else if (measuredWidth == 0){ //Width set to wrap_content
int height = measuredHeight;
int width = height * drawable.getIntrinsicWidth() / drawable.getIntrinsicHeight();
setMeasuredDimension(width, height);
} else { //Width and height are explicitly set (either to match_parent or to exact value)
setMeasuredDimension(measuredWidth, measuredHeight);
}
}
} catch (Exception e) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}


}

因此,如果(例如)将ImageView放入ScrollView中,则ImageView将被正确缩放,并且不会有维度问题

我做了类似于上面的事情,然后把我的头撞在墙上几个小时,因为它在RelativeLayout中不起作用。我最终得到了以下代码:

package com.example;


import android.content.Context;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.ImageView;


public class ScaledImageView extends ImageView {
public ScaledImageView(final Context context, final AttributeSet attrs) {
super(context, attrs);
}


@Override
protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
final Drawable d = getDrawable();


if (d != null) {
int width;
int height;
if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY) {
height = MeasureSpec.getSize(heightMeasureSpec);
width = (int) Math.ceil(height * (float) d.getIntrinsicWidth() / d.getIntrinsicHeight());
} else {
width = MeasureSpec.getSize(widthMeasureSpec);
height = (int) Math.ceil(width * (float) d.getIntrinsicHeight() / d.getIntrinsicWidth());
}
setMeasuredDimension(width, height);
} else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
}

然后为了防止RelativeLayout忽略测量的维度,我这样做:

    <FrameLayout
android:id="@+id/image_frame"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="@+id/something">


<com.example.ScaledImageView
android:id="@+id/image"
android:layout_width="wrap_content"
android:layout_height="150dp"/>
</FrameLayout>

不使用任何自定义类或库:

<ImageView
android:id="@id/img"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:scaleType="fitCenter" />

scaleType="fitCenter"(省略时默认值)

  • 将使它的宽度作为父允许和上升/下降规模,需要保持纵横比。

scaleType="centerInside"

  • 如果src的固有宽度小于父width
    将图像水平居中
  • 如果src的固有宽度大于父类width
    将使其与父类允许的宽度一样宽,并按比例减小宽高比。

不管你使用的是android:src还是ImageView.setImage*方法,键都可能是adjustViewBounds

使用android:scaleType="centerCrop"

只需使用UniversalImageLoader并设置

DisplayImageOptions.Builder()
.imageScaleType(ImageScaleType.EXACTLY_STRETCHED)
.build();

ImageView上没有缩放设置

使用ImageView中的这些属性来保持纵横比:

android:adjustViewBounds="true"
android:scaleType="fitXY"

试试这个:它为我解决了问题

   android:adjustViewBounds="true"
android:scaleType="fitXY"

你不需要任何java代码。你只需要:

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

键在width和height的匹配父项中

如果你在ImageView中将图像设置为背景,这将不适用,需要在src(android:src)设置。

谢谢。

要创建宽度等于屏幕宽度的图像,并且根据纵横比按比例设置高度,请执行以下操作。

Glide.with(context).load(url).asBitmap().into(new SimpleTarget<Bitmap>() {
@Override
public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) {


// creating the image that maintain aspect ratio with width of image is set to screenwidth.
int width = imageView.getMeasuredWidth();
int diw = resource.getWidth();
if (diw > 0) {
int height = 0;
height = width * resource.getHeight() / diw;
resource = Bitmap.createScaledBitmap(resource, width, height, false);
}
imageView.setImageBitmap(resource);
}
});

希望这能有所帮助。

试着用这简单的线条…在图像视图标签的XML代码中添加这一行,而不添加任何依赖项 android: scaleType = " fitXY " < / p >

使用android:ScaleType="fitXY" im ImageView xml

我有一个类似的问题,我发现这是因为你需要计算dp的原因。当你从drawable加载它时,Android studio会计算ImageView,但当你使用另一种方法,比如从位图加载时,dp不会自动计算,

这是我的xml

<ImageView
android:id="@+id/imageViewer"
android:layout_width="match_parent"
android:layout_height="match_parent"//dp is not automaticly updated, when loading from a other source
android:scaleType="fitCenter"
tools:srcCompat="@drawable/a8" />

我使用Kotlin,并从资产文件加载可绘制的,这是我如何计算这一点

val d = Drawable.createFromStream(assets.open("imageData/${imageName}.png"), null)
bitHeight = d.minimumHeight//get the image height
imageViewer.layoutParams.height = (bitHeight * resources.displayMetrics.density).toInt()//set the height
imageViewer.setImageDrawable(d)//set the image from the drawable
imageViewer.requestLayout()//here I apply it to the layout

FOR IMAGE VIEW(设置这些参数)

android:layout_width     = "match_parent"
android:layout_height    = "wrap_content"
android:scaleType        = "fitCenter"
android:adjustViewBounds = "true"

不管图像的大小是多少,它的宽度会匹配父元素高度会根据比例匹配。我已经测试过了,我百分百确定。

我们想要这个>adjustViewBound = true

不是这个——>adjustViewBound = false

// Results will be:
Image width -> stretched as match parent
Image height -> according to image width (maximum to aspect ratio)


// like the first one