Часто спрашивают, но никогда не отвечают (по крайней мере, в воспроизводимой форме).
У меня есть представление изображения с изображением, которое меньше, чем представление. Я хочу масштабировать изображение по ширине экрана и настроить высоту 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
, как предлагалось в другом месте, снова не имеет никакого эффекта.
Я пробовал другие комбинации - безрезультатно. Итак, пожалуйста, кто-нибудь знает:
Как настроить XML ImageView для заполнения ширины экрана, масштабирования меньшего изображения для заполнения всего вида, отображения изображения с его соотношением сторон без искажения или обрезки?
РЕДАКТИРОВАТЬ: Я также попытался установить произвольную числовую высоту. Это влияет только на centerCrop
настройку. Изображение будет искажено по вертикали в соответствии с высотой обзора.
android:scaleType="fitCenter"
?Ответы:
Я решил это, создав 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" />
источник
Это небольшое дополнение к отличному решению Марка Мартинссона.
Если ширина вашего изображения больше его высоты, то решение Марка оставит пространство вверху и внизу экрана.
Приведенное ниже исправляет это, сначала сравнивая ширину и высоту: если ширина изображения> = height, тогда оно масштабирует высоту в соответствии с высотой экрана, а затем масштабирует ширину, чтобы сохранить соотношение сторон. Точно так же, если высота изображения> ширины, тогда оно будет масштабировать ширину в соответствии с шириной экрана, а затем масштабировать высоту, чтобы сохранить соотношение сторон.
Другими словами, он полностью удовлетворяет определению
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>
источник
Котлинская версия ответа Марка Мартинссона :
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) } }
источник
Еще одно дополнение к решению Марка Матинссона. Я обнаружил, что некоторые из моих изображений были перемасштабированы, чем другие. Поэтому я изменил класс так, чтобы изображение масштабировалось с максимальным коэффициентом. Если изображение слишком мало для масштабирования по максимальной ширине без размытия, оно перестает масштабироваться за пределы максимального предела.
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); } } }
источник