Ответ 1
В стандарте макета XML нет жизнеспособного решения.
Единственный надежный способ реагирования на размер динамического изображения - использовать LayoutParams
в коде.
Неудовлетворительно.
Часто спрашивали, никогда не отвечали (по крайней мере, не воспроизводимым образом).
У меня есть изображение с изображением меньше, чем представление. Я хочу масштабировать изображение по ширине экрана и отрегулировать высоту 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 для заполнения ширины экрана, масштабировать меньшее изображение, чтобы заполнить весь вид, отображая изображение с его форматным соотношением без искажений или обрезки?
EDIT: Я также попытался установить произвольную числовую высоту. Это влияет только на настройку centerCrop
. Он будет искажать изображение по вертикали в соответствии с высотой обзора.
В стандарте макета XML нет жизнеспособного решения.
Единственный надежный способ реагирования на размер динамического изображения - использовать LayoutParams
в коде.
Неудовлетворительно.
Я решил это, создав класс 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" />
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" />
Это небольшое дополнение к отличному решению Марка Мартинсона.
Если ширина вашего изображения больше его высоты, тогда решение Mark останется в верхнем и нижнем углу экрана.
Ниже описано это, сначала сравнивая ширину и высоту: если ширина изображения >= высота, то она будет масштабировать высоту в соответствии с высотой экрана, а затем масштабировать ширину, чтобы сохранить соотношение сторон. Аналогично, если высота изображения > ширина, то она будет масштабировать ширину, чтобы она соответствовала ширине экрана, а затем масштабировала высоту, чтобы сохранить соотношение сторон.
Другими словами, он правильно удовлетворяет определению 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. Например:.
<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);
}
}
}