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


как сделать фоновое изображение в соответствии с видом, но сохранить его соотношение сторон при использовании <bitmap /> в качестве фона drawable XML? Ни один из <bitmap> ' s android:gravity значения дают желаемый эффект.

9 53

9 ответов:

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

  1. вырезать/масштабирование растрового изображения программными средствами с Bitmap.createScaledBitmap(Bitmap src, int dstWidth, int dstHeight, boolean filter) и установить его как некоторые View'ы фона.

  2. вы используете 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>
    

есть простой способ сделать это из 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.

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

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

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

надеюсь, вы поняли идею.

Я хотел сделать что-то подобное в моем пользовательском 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);
            }
        }
    }
}

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

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

android:scaleType="centerCrop"

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

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

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

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

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

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

старый вопрос, но ни один из ответов работал для меня. Однако этот 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>

если растровое изображение шире, чем в высоту, используйте android:gravity="fill_vertical". В противном случае, используйте android:gravity="fill_horizontal". Это имеет тот же эффект, что и использование 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 папка и другая в .

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

здесь я установил одинаковую ширину и высоту для квадратных изображений [или вы можете wrap_content на обоих].

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

    <ImageView
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:layout_alignParentTop="true"
        android:adjustViewBounds="true"
        android:scaleType="fitCenter"
        android:src="@drawable/background_image"/> 

</RelativeLayout>

настроить вид границы и масштабы центр тип подходит делать трюк.