Often asked, never answered (at least not in a reproducible way).
经常被问到,从来没有回答过(至少不是以可重复的方式)。
I have an image view with an image that is smaller than the view. I want to scale the image to the width of the screen and adjust the height of the ImageView to reflect the proportionally correct height of the image.
我有一个图像视图,其图像小于视图。我想将图像缩放到屏幕的宽度,并调整ImageView的高度以反映图像的比例正确高度。
<ImageView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
This results in the image centered at its original size (smaller then the screen width) with margins at the side. No good.
这导致图像以其原始大小(小于屏幕宽度)为中心,边缘为边缘。不好。
So I added
所以我补充道
android:adjustViewBounds="true"
Same effect, no good. I added
效果相同,没有好处。我补充道
android:scaleType="centerInside"
Same effect, no good. I changed centerInside
to fitCenter
. Same effect, no good. I changed centerInside
to centerCrop
.
效果相同,没有好处。我将centerInside改为fitCenter。效果相同,没有好处。我将centerInside改为centerCrop。
android:scaleType="centerCrop"
Now, finally, the image is scaled to the width of the screen - but cropped at top and bottom! So I changed centerCrop
to fitXY
.
现在,最后,图像缩放到屏幕的宽度 - 但在顶部和底部裁剪!所以我将centerCrop改为fitXY。
android:scaleType="fitXY"
Now the image is scaled to the width of the screen but not scaled on the y-axis, resulting in a distorted image.
现在,图像缩放到屏幕的宽度,但没有在y轴上缩放,导致图像失真。
Removing android:adjustViewBounds="true"
has no effect. Adding an android:layout_gravity
, as suggested elsewhere, has again no effect.
删除android:adjustViewBounds =“true”无效。添加android:layout_gravity,如其他地方所建议的,再次没有效果。
I have tried other combinations -- to no avail. So, please does anyone know:
我尝试过其他组合 - 无济于事。所以,请有人知道:
How do you set up the XML of an ImageView to fill the width of the screen, scale a smaller image to fill the entire view, displaying the image with its aspect ratio without distortion or cropping?
如何设置ImageView的XML来填充屏幕的宽度,缩放较小的图像以填充整个视图,显示具有宽高比的图像而不会失真或裁剪?
EDIT: I also tried setting an arbitrary numeric height. This only has an effect with the centerCrop
setting. It will distort the image vertically according to the view height.
编辑:我也尝试设置任意数字高度。这仅对centerCrop设置有效。它会根据视图高度垂直扭曲图像。
8 个解决方案
#1
107
I have solved this by creating a java-class that you include in your layout-file:
我通过创建一个包含在layout-file中的java类来解决这个问题:
public class DynamicImageView extends ImageView {
public DynamicImageView(final Context context, final AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
final Drawable d = this.getDrawable();
if (d != null) {
// ceil not round - avoid thin vertical gaps along the left/right edges
final int width = MeasureSpec.getSize(widthMeasureSpec);
final int height = (int) Math.ceil(width * (float) d.getIntrinsicHeight() / d.getIntrinsicWidth());
this.setMeasuredDimension(width, height);
} else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
}
Now, you use this by added your class to your layout-file:
现在,您通过将您的类添加到布局文件中来使用它:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<my.package.name.DynamicImageView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:scaleType="centerCrop"
android:src="@drawable/about_image" />
</RelativeLayout>
#2
27
I had the same problem, as yours. After 30 minutes of trying diffirent variations I solved the problem in this way. It gives you the flexible height, and width adjusted to the parent width
我和你的问题一样。在尝试不同变化30分钟后,我以这种方式解决了问题。它为您提供灵活的高度,宽度调整为父宽度
<ImageView
android:id="@+id/imageview_company_logo"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:adjustViewBounds="true"
android:scaleType="fitCenter"
android:src="@drawable/appicon" />
#3
19
There is no viable solution within the XML layout standard.
XML布局标准中没有可行的解决方案。
The only reliable way to react to a dynamic image size is to use LayoutParams
in code.
对动态图像大小做出反应的唯一可靠方法是在代码中使用LayoutParams。
Disappointing.
令人失望。
#4
7
android:scaleType="fitCenter"
Compute a scale that will maintain the original src aspect ratio, but will also ensure that src fits entirely inside dst. At least one axis (X or Y) will fit exactly. The result is centered inside dst.
计算将保持原始src宽高比的比例,但也将确保src完全适合dst。至少一个轴(X或Y)将精确匹配。结果集中在dst内。
edit:
编辑:
The problem here is that the layout_height="wrap_content"
is not "allowing" the image to expand. You'll have to set a size for it, for that change
这里的问题是layout_height =“wrap_content”不是“允许”图像扩展。对于该更改,您必须为其设置大小
android:layout_height="wrap_content"
to
至
android:layout_height="100dp" // or whatever size you want it to be
edit2:
EDIT2:
works fine:
工作正常:
<ImageView
android:id="@+id/imageView1"
android:layout_width="match_parent"
android:layout_height="300dp"
android:scaleType="fitCenter"
android:src="@drawable/img715945m" />
#5
7
This is a small addition to Mark Martinsson's excellent solution.
这是Mark Martinsson优秀解决方案的一小部分。
If your image's width is larger than its height, then Mark's solution will leave space at the top and bottom of the screen.
如果图像的宽度大于其高度,那么Mark的解决方案将在屏幕的顶部和底部留出空间。
The below fixes this by first comparing the width and height: if the image width >= height, then it will scale the height to match the screen height, and then scale the width to preserve the aspect ratio. Similarly, if the image height > width, then it will scale the width to match the screen width and then scale the height to preserve the aspect ratio.
下面通过首先比较宽度和高度来解决这个问题:如果图像宽度> =高度,那么它将缩放高度以匹配屏幕高度,然后缩放宽度以保持纵横比。同样,如果图像高度>宽度,则它将缩放宽度以匹配屏幕宽度,然后缩放高度以保持纵横比。
In other words, it properly satisfies the definition of scaleType="centerCrop"
:
换句话说,它恰当地满足scaleType =“centerCrop”的定义:
http://developer.android.com/reference/android/widget/ImageView.ScaleType.html
http://developer.android.com/reference/android/widget/ImageView.ScaleType.html
Scale the image uniformly (maintain the image's aspect ratio) so that both dimensions (width and height) of the image will be equal to or larger than the corresponding dimension of the view (minus padding).
均匀缩放图像(保持图像的纵横比),使图像的尺寸(宽度和高度)等于或大于视图的相应尺寸(减去填充)。
package com.mypackage;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.ImageView;
public class FixedCenterCrop extends ImageView
{
public FixedCenterCrop(final Context context, final AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec)
{
final Drawable d = this.getDrawable();
if(d != null) {
int height = MeasureSpec.getSize(heightMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
if(width >= height)
height = (int) Math.ceil(width * (float) d.getIntrinsicHeight() / d.getIntrinsicWidth());
else
width = (int) Math.ceil(height * (float) d.getIntrinsicWidth() / d.getIntrinsicHeight());
this.setMeasuredDimension(width, height);
} else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
}
This solution automatically works in either portrait or landscape mode. You reference it in your layout just as you do in Mark's solution. E.g.:
此解决方案自动以纵向或横向模式运行。您可以像在Mark的解决方案中一样在布局中引用它。例如。:
<com.mypackage.FixedCenterCrop
android:id="@+id/imgLoginBackground"
android:src="@drawable/mybackground"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:scaleType="centerCrop" />
#6
3
I ran into the same problem, but with a fixed height, scaled width keeping the image's original aspect ratio. I solved it via a weighted linear layout. You can hopefully modify it for your needs.
我遇到了同样的问题,但是固定高度,缩放宽度保持图像的原始宽高比。我通过加权线性布局解决了这个问题。您可以根据需要修改它。
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:id="@+id/image"
android:layout_width="0px"
android:layout_height="180dip"
android:layout_weight="1.0"
android:adjustViewBounds="true"
android:scaleType="fitStart" />
</LinearLayout>
#7
0
One more addition to Mark Matinsson's solution. I found that some of my images were over scaled than others. So I modified the class so that the image is scaled by a maximum factor. If the image is too small to be scaled at max width without becoming blurry, it stops scaling beyond the max limit.
Mark Matinsson解决方案的另一个补充。我发现我的一些图像比其他图像过度缩放。所以我修改了类,以便通过最大因子缩放图像。如果图像太小而无法在最大宽度上缩放而不会变得模糊,则会停止缩放超出最大限制。
public class DynamicImageView extends ImageView {
final int MAX_SCALE_FACTOR = 2;
public DynamicImageView(final Context context) {
super(context);
}
@Override
protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
final Drawable d = this.getDrawable();
if (d != null) {
// ceil not round - avoid thin vertical gaps along the left/right edges
int width = View.MeasureSpec.getSize(widthMeasureSpec);
if (width > (d.getIntrinsicWidth()*MAX_SCALE_FACTOR)) width = d.getIntrinsicWidth()*MAX_SCALE_FACTOR;
final int height = (int) Math.ceil(width * (float) d.getIntrinsicHeight() / d.getIntrinsicWidth());
this.setMeasuredDimension(width, height);
} else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
}
}
#8
0
Kotlin version of Mark Martinsson's answer:
Kotlin版Mark Martinsson的回答:
class DynamicImageView(context: Context, attrs: AttributeSet) : AppCompatImageView(context, attrs) {
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
val drawable = this.drawable
if (drawable != null) {
//Ceil not round - avoid thin vertical gaps along the left/right edges
val width = View.MeasureSpec.getSize(widthMeasureSpec)
val height = Math.ceil((width * drawable.intrinsicHeight.toFloat() / drawable.intrinsicWidth).toDouble()).toInt()
this.setMeasuredDimension(width, height)
} else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
}
}
#1
107
I have solved this by creating a java-class that you include in your layout-file:
我通过创建一个包含在layout-file中的java类来解决这个问题:
public class DynamicImageView extends ImageView {
public DynamicImageView(final Context context, final AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
final Drawable d = this.getDrawable();
if (d != null) {
// ceil not round - avoid thin vertical gaps along the left/right edges
final int width = MeasureSpec.getSize(widthMeasureSpec);
final int height = (int) Math.ceil(width * (float) d.getIntrinsicHeight() / d.getIntrinsicWidth());
this.setMeasuredDimension(width, height);
} else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
}
Now, you use this by added your class to your layout-file:
现在,您通过将您的类添加到布局文件中来使用它:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<my.package.name.DynamicImageView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:scaleType="centerCrop"
android:src="@drawable/about_image" />
</RelativeLayout>
#2
27
I had the same problem, as yours. After 30 minutes of trying diffirent variations I solved the problem in this way. It gives you the flexible height, and width adjusted to the parent width
我和你的问题一样。在尝试不同变化30分钟后,我以这种方式解决了问题。它为您提供灵活的高度,宽度调整为父宽度
<ImageView
android:id="@+id/imageview_company_logo"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:adjustViewBounds="true"
android:scaleType="fitCenter"
android:src="@drawable/appicon" />
#3
19
There is no viable solution within the XML layout standard.
XML布局标准中没有可行的解决方案。
The only reliable way to react to a dynamic image size is to use LayoutParams
in code.
对动态图像大小做出反应的唯一可靠方法是在代码中使用LayoutParams。
Disappointing.
令人失望。
#4
7
android:scaleType="fitCenter"
Compute a scale that will maintain the original src aspect ratio, but will also ensure that src fits entirely inside dst. At least one axis (X or Y) will fit exactly. The result is centered inside dst.
计算将保持原始src宽高比的比例,但也将确保src完全适合dst。至少一个轴(X或Y)将精确匹配。结果集中在dst内。
edit:
编辑:
The problem here is that the layout_height="wrap_content"
is not "allowing" the image to expand. You'll have to set a size for it, for that change
这里的问题是layout_height =“wrap_content”不是“允许”图像扩展。对于该更改,您必须为其设置大小
android:layout_height="wrap_content"
to
至
android:layout_height="100dp" // or whatever size you want it to be
edit2:
EDIT2:
works fine:
工作正常:
<ImageView
android:id="@+id/imageView1"
android:layout_width="match_parent"
android:layout_height="300dp"
android:scaleType="fitCenter"
android:src="@drawable/img715945m" />
#5
7
This is a small addition to Mark Martinsson's excellent solution.
这是Mark Martinsson优秀解决方案的一小部分。
If your image's width is larger than its height, then Mark's solution will leave space at the top and bottom of the screen.
如果图像的宽度大于其高度,那么Mark的解决方案将在屏幕的顶部和底部留出空间。
The below fixes this by first comparing the width and height: if the image width >= height, then it will scale the height to match the screen height, and then scale the width to preserve the aspect ratio. Similarly, if the image height > width, then it will scale the width to match the screen width and then scale the height to preserve the aspect ratio.
下面通过首先比较宽度和高度来解决这个问题:如果图像宽度> =高度,那么它将缩放高度以匹配屏幕高度,然后缩放宽度以保持纵横比。同样,如果图像高度>宽度,则它将缩放宽度以匹配屏幕宽度,然后缩放高度以保持纵横比。
In other words, it properly satisfies the definition of scaleType="centerCrop"
:
换句话说,它恰当地满足scaleType =“centerCrop”的定义:
http://developer.android.com/reference/android/widget/ImageView.ScaleType.html
http://developer.android.com/reference/android/widget/ImageView.ScaleType.html
Scale the image uniformly (maintain the image's aspect ratio) so that both dimensions (width and height) of the image will be equal to or larger than the corresponding dimension of the view (minus padding).
均匀缩放图像(保持图像的纵横比),使图像的尺寸(宽度和高度)等于或大于视图的相应尺寸(减去填充)。
package com.mypackage;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.ImageView;
public class FixedCenterCrop extends ImageView
{
public FixedCenterCrop(final Context context, final AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec)
{
final Drawable d = this.getDrawable();
if(d != null) {
int height = MeasureSpec.getSize(heightMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
if(width >= height)
height = (int) Math.ceil(width * (float) d.getIntrinsicHeight() / d.getIntrinsicWidth());
else
width = (int) Math.ceil(height * (float) d.getIntrinsicWidth() / d.getIntrinsicHeight());
this.setMeasuredDimension(width, height);
} else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
}
This solution automatically works in either portrait or landscape mode. You reference it in your layout just as you do in Mark's solution. E.g.:
此解决方案自动以纵向或横向模式运行。您可以像在Mark的解决方案中一样在布局中引用它。例如。:
<com.mypackage.FixedCenterCrop
android:id="@+id/imgLoginBackground"
android:src="@drawable/mybackground"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:scaleType="centerCrop" />
#6
3
I ran into the same problem, but with a fixed height, scaled width keeping the image's original aspect ratio. I solved it via a weighted linear layout. You can hopefully modify it for your needs.
我遇到了同样的问题,但是固定高度,缩放宽度保持图像的原始宽高比。我通过加权线性布局解决了这个问题。您可以根据需要修改它。
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:id="@+id/image"
android:layout_width="0px"
android:layout_height="180dip"
android:layout_weight="1.0"
android:adjustViewBounds="true"
android:scaleType="fitStart" />
</LinearLayout>
#7
0
One more addition to Mark Matinsson's solution. I found that some of my images were over scaled than others. So I modified the class so that the image is scaled by a maximum factor. If the image is too small to be scaled at max width without becoming blurry, it stops scaling beyond the max limit.
Mark Matinsson解决方案的另一个补充。我发现我的一些图像比其他图像过度缩放。所以我修改了类,以便通过最大因子缩放图像。如果图像太小而无法在最大宽度上缩放而不会变得模糊,则会停止缩放超出最大限制。
public class DynamicImageView extends ImageView {
final int MAX_SCALE_FACTOR = 2;
public DynamicImageView(final Context context) {
super(context);
}
@Override
protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
final Drawable d = this.getDrawable();
if (d != null) {
// ceil not round - avoid thin vertical gaps along the left/right edges
int width = View.MeasureSpec.getSize(widthMeasureSpec);
if (width > (d.getIntrinsicWidth()*MAX_SCALE_FACTOR)) width = d.getIntrinsicWidth()*MAX_SCALE_FACTOR;
final int height = (int) Math.ceil(width * (float) d.getIntrinsicHeight() / d.getIntrinsicWidth());
this.setMeasuredDimension(width, height);
} else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
}
}
#8
0
Kotlin version of Mark Martinsson's answer:
Kotlin版Mark Martinsson的回答:
class DynamicImageView(context: Context, attrs: AttributeSet) : AppCompatImageView(context, attrs) {
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
val drawable = this.drawable
if (drawable != null) {
//Ceil not round - avoid thin vertical gaps along the left/right edges
val width = View.MeasureSpec.getSize(widthMeasureSpec)
val height = Math.ceil((width * drawable.intrinsicHeight.toFloat() / drawable.intrinsicWidth).toDouble()).toInt()
this.setMeasuredDimension(width, height)
} else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
}
}