Масштабировать изображение, сохраняя его соотношение сторон в фоновом режиме

Как сделать фоновое изображение подходящим для представления, но сохранить его соотношение сторон при использовании <bitmap /> в качестве фонового рисунка xml? Ни один из значений <bitmap> android:gravity не дает желаемого эффекта.

Ответ 1

Невозможно добиться манипулирования фоновым атрибутом только в xml файлах. Существует два варианта:

  • Вы сокращаете или масштабируете растровое изображение программно с помощью Bitmap.createScaledBitmap(Bitmap src, int dstWidth, int dstHeight, boolean filter) и установите его как некоторый фон View.

  • Вы используете ImageView вместо фона, помещая его в качестве первого элемента макета и укажите для него android:scaleType:

    <RelativeLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" >
    
        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
    
            android:src="@drawable/backgrnd"
            android:scaleType="centerCrop" />
    
        ...
    
        rest layout components here
    
        ...
    
    </RelativeLayout>
    

Ответ 2

Существует простой способ сделать это из drawable:

your_drawable.xml

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >

    <item android:drawable="@color/bg_color"/>
    <item>
        <bitmap
            android:gravity="center|bottom|clip_vertical"
            android:src="@drawable/your_image" />
    </item>

</layer-list>

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

Другой способ - просто создать макет, где вы будете использовать ImageView и установите scaleType на fitCenter.

Надеемся, что эта информация поможет вам достичь желаемого.

Ответ 3

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

Вы могли бы сосредоточить его на содержании, поместив 9-патч-точки в углах, которые сохранят ваше соотношение (если внешний край вашего изображения будет повторяемым/прозрачным).

Надеюсь, вы получите эту идею.

Ответ 4

Использование метода, описанного a.ch, отлично подойдет для меня, за исключением того, что я использовал этот тип шкалы, который работал намного лучше для того, что мне было нужно:

android:scaleType="centerCrop"

Вот полный список доступных типов шкалы: http://developer.android.com/reference/android/widget/ImageView.ScaleType.html

Ответ 5

Попробуйте использовать InsetDrawable (хорошо работает для меня).

Просто отрисуйте эту выбируемую и вставку (или прописку), которую вы хотите с любой из четырех сторон.

InsetDrawable insetDrawable = new InsetDrawable(drawable, insetLeft, insetTop, insetRight, insetBottom);

Он специально используется для настройки фонового рисунка, размера меньшего размера или вида.

См. здесь: https://developer.android.com/reference/android/graphics/drawable/InsetDrawable.html

Ответ 6

Старый вопрос, но ни один из других ответов не работал у меня. Однако этот xml-код:

<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_alignParentTop="true"
        android:scaleType="centerCrop"
        android:src="@drawable/background_image"/> 

</RelativeLayout>

Ответ 7

Если ваш растровый рисунок шире, чем высокий, используйте android:gravity="fill_vertical". В противном случае используйте android:gravity="fill_horitzonal". Это похоже на использование android:scaleType="centerCrop" на ImageView.

<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
    android:gravity="fill_vertical"
    android:src="@drawable/image" />

Если вы поддерживаете несколько ориентаций, вы можете создать один растровый XML файл в папке drawable-port, а другой в папке drawable-land.

Ответ 8

Я хотел сделать что-то подобное в моем классе Drawable. Вот важные части:

public class CustomBackgroundDrawable extends Drawable
{
    private Rect mTempRect = new Rect();
    private Paint mBitmapPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

    ...

public void draw(@NonNull Canvas canvas)
{
    Rect bounds = getBounds();
    if (mBitmap != null ) {
        if (mScaleType == ScaleType.SCALE_FILL) {
            //bitmap scales to fill the whole bounds area (bitmap can be cropped)
            if (bounds.height() > 0 && bounds.height() > 0) {
                float scale = Math.min(mBitmap.getWidth()/(float)bounds.width(), mBitmap.getHeight()/(float)bounds.height());

                float bitmapVisibleWidth = scale * bounds.width();
                float bitmapVisibleHeight = scale * bounds.height();

                mTempRect.set((int)(mBitmap.getWidth()-bitmapVisibleWidth)/2, 0, (int)(bitmapVisibleWidth+mBitmap.getWidth())/2, (int)bitmapVisibleHeight);
                canvas.drawBitmap(mBitmap, mTempRect, bounds, mBitmapPaint);
            }
        } else if (mScaleType == ScaleType.SCALE_FIT) {
            //bitmap scales to fit in bounds area
            if (bounds.height() > 0 && bounds.height() > 0) {
                float scale = Math.min((float)bounds.width()/mBitmap.getWidth(), (float)bounds.height()/mBitmap.getHeight());

                float bitmapScaledWidth = scale * mBitmap.getWidth();
                float bitmapScaledHeight = scale * mBitmap.getHeight();
                int centerPadding = (int)(bounds.width()-bitmapScaledWidth)/2;
                mTempRect.set(bounds.left + centerPadding, bounds.top, bounds.right - centerPadding, bounds.top+(int)bitmapScaledHeight);
                canvas.drawBitmap(mBitmap, null, mTempRect, mBitmapPaint);
            }
        }
    }
}

При таком подходе вы гибки, чтобы применять любую требуемую шкалу.