Escalar la imagen manteniendo su relación de aspecto en el fondo dibujable


¿Cómo hago que una imagen de fondo se ajuste a la vista pero mantenga su relación de aspecto cuando uso <bitmap /> como XML de elemento de diseño de fondo? Ninguno de los valores de <bitmap> da el efecto deseado.

Author: wonea, 2012-03-27

9 answers

Es imposible lograr manipular el atributo background solo dentro de los archivos xml. Hay dos opciones:

  1. Puede cortar / escalar el mapa de bits mediante programación con Bitmap.createScaledBitmap(Bitmap src, int dstWidth, int dstHeight, boolean filter) y ponlo como fondo de algún View.

  2. Se usa ImageView en lugar de background colocándolo como el primer elemento del layout y especificando android:scaleType atributo para ello:

    <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>
    
 50
Author: a.ch.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-02-05 08:34:28

Hay una manera fácil de hacer esto desde el elemento de diseño:

Su_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>

El único inconveniente es que si no hay suficiente espacio, su imagen no se mostrará completamente, pero se recortará, no pude encontrar una manera de hacer esto directamente desde un elemento de diseño. Pero de las pruebas que hice funciona bastante bien, y no corta mucho de la imagen. Podrías jugar más con las opciones de gravedad.

Otra forma será simplemente crear un diseño, donde se utilice un ImageView y establecer el scaleType to fitCenter.

Espero que esta información le ayude a lograr lo que desea.

 31
Author: Ionut Negru,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-02-21 09:05:47

Otro enfoque sería crear imágenes de parche 9 de su imagen normal y hacerla estirar la escala de la manera que desee.

Puede hacer que centre el contenido poniendo 9 puntos de parche en las esquinas que preservarán su relación obviamente (suponiendo que el borde más exterior de su imagen sea repetible/transparente).

Espero que tengas la idea.

 3
Author: xbakesx,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-09-12 20:49:52

Quería hacer algo similar en mi clase de elementos de diseño personalizados. Aquí están las piezas importantes:

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

Con este enfoque eres flexible para aplicar cualquier lógica de escala que necesites

 3
Author: Kamen Dobrev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-23 12:54:33

Utilizando el método descrito por a.ch funcionó muy bien para mí, excepto que usé este tipo de escala que funcionó mucho mejor para lo que necesitaba:

android:scaleType="centerCrop"

Aquí está una lista completa de los tipos de escala disponibles: http://developer.android.com/reference/android/widget/ImageView.ScaleType.html

 2
Author: Benjamin Stark,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-12 17:02:30

Intente usar InsetDrawable (funcionó bien para mí).

Simplemente dale a este tu elemento de diseño, y las inserciones (o relleno) que quieras de cualquiera de los cuatro lados.

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

Se usa específicamente para configurar el elemento de diseño de fondo, de tamaño más pequeño o que la vista.

Ver Aquí : https://developer.android.com/reference/android/graphics/drawable/InsetDrawable.html

 1
Author: Ashutosh Chamoli,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-13 08:51:29

Vieja pregunta, pero ninguna de las otras respuestas funcionó para mí. Este código xml hizo sin embargo:

<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>
 1
Author: Incinerator,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-07 15:24:41

Si su mapa de bits es más ancho que alto, use android:gravity="fill_vertical". De lo contrario, utilice android:gravity="fill_horizontal". Esto tiene un efecto similar al uso de android:scaleType="centerCrop" en un ImageView.

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

Si admite varias orientaciones, puede crear un archivo XML de mapa de bits en la carpeta drawable-port y el otro en la carpeta drawable-land.

 1
Author: Jason Robinson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-15 02:28:58

Para ajustar la imagen al espacio disponible (o si ha establecido ancho y alto en dp), he probado este enfoque si la imagen no es demasiado ancha.

Aquí he establecido el mismo ancho y alto para las imágenes cuadradas [o puede wrap_content en ambos].

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

Ajustar los límites de la vista y el ajuste central del tipo de escala hacen el truco.

 0
Author: Abhinav Saxena,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-05-30 04:56:52