Подтвердить что ты не робот

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

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

У меня есть изображение с изображением меньше, чем представление. Я хочу масштабировать изображение по ширине экрана и отрегулировать высоту 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. Он будет искажать изображение по вертикали в соответствии с высотой обзора.

4b9b3361

Ответ 1

В стандарте макета XML нет жизнеспособного решения.

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

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

Ответ 2

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

Ответ 3

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

Ответ 4

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

Ответ 5

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

Если ширина вашего изображения больше его высоты, тогда решение 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" />

Ответ 6

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

<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

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

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

}