Android ImageView масштабирует меньшее изображение до ширины с гибкой высотой без обрезки или искажения

Часто спрашивали, никогда не отвечали (по крайней мере, не воспроизводимым образом).

У меня есть изображение с изображением, которое меньше, чем представление. Я хочу масштабировать изображение по ширине экрана и регулировать высоту ImageView, чтобы отразить пропорционально правильную высоту изображения.

<ImageView android:layout_width="fill_parent" android:layout_height="wrap_content" /> 

Это приводит к тому, что изображение с центром в исходном размере (меньше ширины экрана) с полями сбоку. Не хорошо.

Поэтому я добавил

 android:adjustViewBounds="true" 

Тот же эффект, ничего хорошего. я добавил

 android:scaleType="centerInside" 

Тот же эффект, ничего хорошего. Я изменил fitCenter чтобы fitCenter . Тот же эффект, ничего хорошего. Я изменил centerCrop на centerCrop .

 android:scaleType="centerCrop" 

Теперь, наконец, изображение масштабируется по ширине экрана, но обрезается сверху и снизу! Поэтому я изменил centerCrop на fitXY .

 android:scaleType="fitXY" 

Теперь изображение масштабируется до ширины экрана, но не масштабируется по оси y, что приводит к искажению изображения.

Удаление android:adjustViewBounds="true" не влияет. Добавление android:layout_gravity , как было предложено в другом месте, снова не влияет.

Я пробовал другие комбинации – безрезультатно. Итак, пожалуйста, кто-нибудь знает:

Как настроить XML ImageView для заполнения ширины экрана, масштабировать меньшее изображение, чтобы заполнить весь вид, отображая изображение с его форматным соотношением без искажений или обрезки?

EDIT: Я также попытался установить произвольную числовую высоту. Это влияет только на настройку centerCrop . Он будет искажать изображение по вертикали в соответствии с высотой обзора.

Solutions Collecting From Web of "Android ImageView масштабирует меньшее изображение до ширины с гибкой высотой без обрезки или искажения"

Я решил это, создав класс 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> 

У меня была такая же проблема, как у вас. После 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" /> 

Стандарт компоновки XML не существует.

Единственный надежный способ реагирования на размер динамического изображения – использовать LayoutParams в коде.

Неудовлетворительно.

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

Это небольшое дополнение к отличному решению Марка Мартинсона.

Если ширина вашего изображения больше, чем его высота, тогда решение Марка останется в верхней и нижней части экрана.

Нижеследующее устанавливает это, сначала сравнивая ширину и высоту: если ширина изображения> = высота, то она будет масштабировать высоту в соответствии с высотой экрана, а затем масштабировать ширину, чтобы сохранить соотношение сторон. Аналогично, если высота изображения> ширина, то она будет масштабировать ширину в соответствии с шириной экрана, а затем масштабировать высоту, чтобы сохранить соотношение сторон.

Другими словами, он правильно удовлетворяет определению 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); } } } 

Это решение автоматически работает в портретном или альбомном режиме. Вы ссылаетесь на него в своем макете так же, как и на решение Марка. Например:

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

Я столкнулся с той же проблемой, но с фиксированной высотой, масштабированной шириной, сохраняющей исходное соотношение сторон изображения. Я решил его с помощью взвешенной линейной компоновки. Вы можете надеяться изменить его для своих нужд.

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

Еще одно дополнение к решению Марка Матинсона. Я обнаружил, что некоторые из моих изображений были более масштабированными, чем другие. Поэтому я модифицировал класс так, чтобы изображение масштабировалось с максимальным коэффициентом. Если изображение слишком мало для масштабирования с максимальной шириной без размытости, оно перестает масштабироваться за пределы максимального предела.

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

}