经常被问到,从未回答过(至少不是以可重复的方式回答)。
我的图像视图的图像比视图小。我想将图像缩放到屏幕的宽度,并调整ImageView的高度以反映图像的比例正确高度。
<ImageView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
这会导致图像以其原始大小为中心(小于屏幕宽度),边缘为边距。不好。
所以我添加了
android:adjustViewBounds="true"
同样的效果,没有好处。我添加了
android:scaleType="centerInside"
同样的效果,没有好处。我将centerInside
更改为fitCenter
。同样的效果,没有好处。我将centerInside
更改为centerCrop
。
android:scaleType="centerCrop"
现在,最后,图像缩放到屏幕宽度 - 但顶部和底部裁剪!所以我将centerCrop
更改为fitXY
。
android:scaleType="fitXY"
现在图像缩放到屏幕宽度,但不在y轴上缩放,导致扭曲图像。
删除android:adjustViewBounds="true"
无效。如其他地方所建议的那样添加android:layout_gravity
再次没有效果。
我尝试过其他组合 - 无济于事。所以,请有人知道:
如何设置ImageView的XML以填充屏幕宽度,缩放较小的图像以填充整个视图,显示具有宽高比的图像而不会失真或裁剪?
编辑:我也尝试设置任意数字高度。这仅对centerCrop
设置有效。它会根据视图高度垂直扭曲图像。
答案 0 :(得分:108)
我通过创建一个包含在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);
}
}
}
现在,您可以通过将您的类添加到布局文件来使用它:
<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>
答案 1 :(得分:32)
我和你的一样有同样的问题。在尝试不同变化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" />
答案 2 :(得分:20)
XML布局标准中没有可行的解决方案。
对动态图像大小做出反应的唯一可靠方法是在代码中使用LayoutParams
。
令人失望。
答案 3 :(得分:8)
android:scaleType="fitCenter"
计算将保持原始src宽高比的比例,但也将确保src完全适合dst。至少一个轴(X或Y)将完全适合。结果集中在dst内。
修改强>
这里的问题是layout_height="wrap_content"
不是“允许”图像扩展。你必须为它做一个大小,为那个改变
android:layout_height="wrap_content"
到
android:layout_height="100dp" // or whatever size you want it to be
<强> EDIT2:强>
工作正常:
<ImageView
android:id="@+id/imageView1"
android:layout_width="match_parent"
android:layout_height="300dp"
android:scaleType="fitCenter"
android:src="@drawable/img715945m" />
答案 4 :(得分:7)
这是Mark Martinsson优秀解决方案的一小部分。
如果您的图片宽度大于其高度,那么Mark的解决方案将在屏幕的顶部和底部留出空间。
下面通过首先比较宽度和高度来解决这个问题:如果图像宽度&gt; =高度,那么它将缩放高度以匹配屏幕高度,然后缩放宽度以保持宽高比。类似地,如果图像高度> width,然后它将缩放宽度以匹配屏幕宽度,然后缩放高度以保持宽高比。
换句话说,它恰当地满足scaleType="centerCrop"
:
http://developer.android.com/reference/android/widget/ImageView.ScaleType.html
均匀缩放图像(保持图像的纵横比)以便 图片的尺寸(宽度和高度)将等于或 大于视图的相应维度(减去填充)。
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);
}
}
}
此解决方案可自动以纵向或横向模式运行。您可以像在Mark的解决方案中一样在布局中引用它。 E.g:
<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" />
答案 5 :(得分:3)
我遇到了同样的问题,但是使用固定的高度,缩放的宽度保持了图像的原始宽高比。我通过加权线性布局解决了这个问题。您可以根据需要修改它。
<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>
答案 6 :(得分:0)
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);
}
}
}
答案 7 :(得分:0)
Kotlin版Mark Martinsson的answer:
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)
}
}