Obtener mapa de bits del elemento de diseño vectorial


En mi aplicación, tengo que establecer un icono grande para una notificación. LargeIcon debe ser un mapa de bits, y mis elementos de diseño son imágenes vectoriales (la nueva característica en Android, ver este enlace) El problema es que cuando intento decodificar un recurso que es una imagen vectorial, obtengo un null devuelto.

Aquí está la muestra de código:

if (BitmapFactory.decodeResource(arg0.getResources(), R.drawable.vector_menu_objectifs) == null)
        Log.d("ISNULL", "NULL");
    else
        Log.d("ISNULL", "NOT NULL");

En esta muestra, cuando reemplace R. drawable.vector_menu_objectifs con una imagen "normal", un png por ejemplo, el resultado no es null (obtengo la correcta bits) ¿Hay algo que me estoy perdiendo?

Author: liltof, 2015-11-13

6 answers

Comprobado en API: 17, 21, 23

public static Bitmap getBitmapFromVectorDrawable(Context context, int drawableId) {
    Drawable drawable = ContextCompat.getDrawable(context, drawableId);
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
        drawable = (DrawableCompat.wrap(drawable)).mutate();
    }

    Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(),
            drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(bitmap);
    drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
    drawable.draw(canvas);

    return bitmap;
}

ACTUALIZACIÓN:

Proyecto gradle:

dependencies {
        classpath 'com.android.tools.build:gradle:2.2.0-alpha5'
    }

Módulo gradle:

android {
    compileSdkVersion 23
    buildToolsVersion '23.0.3'
    defaultConfig {
        minSdkVersion 16
        targetSdkVersion 23
        vectorDrawables.useSupportLibrary = true
    }
    ...
}
...
 127
Author: Alexey,
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-19 20:39:44

Puede utilizar el siguiente método:

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private static Bitmap getBitmap(VectorDrawable vectorDrawable) {
    Bitmap bitmap = Bitmap.createBitmap(vectorDrawable.getIntrinsicWidth(),
            vectorDrawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(bitmap);
    vectorDrawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
    vectorDrawable.draw(canvas);
    return bitmap;
}

Que a veces combino con:

private static Bitmap getBitmap(Context context, int drawableId) {
    Drawable drawable = ContextCompat.getDrawable(context, drawableId);
    if (drawable instanceof BitmapDrawable) {
        return ((BitmapDrawable) drawable).getBitmap();
    } else if (drawable instanceof VectorDrawable) {
        return getBitmap((VectorDrawable) drawable);
    } else {
        throw new IllegalArgumentException("unsupported drawable type");
    }
}
 54
Author: snodnipper,
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
2016-02-11 19:14:18

Basado en las respuestas anteriores se puede simplificar así para que coincida con VectorDrawable y BitmapDrawable y para ser compatible con al menos API 15.

public static Bitmap getBitmapFromDrawable(Context context, @DrawableRes int drawableId) {
    Drawable drawable = AppCompatResources.getDrawable(context, drawableId);

    if (drawable instanceof BitmapDrawable) {
        return ((BitmapDrawable) drawable).getBitmap();
    } else if (drawable instanceof VectorDrawableCompat || drawable instanceof VectorDrawable) {
        Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
        drawable.draw(canvas);

        return bitmap;
    } else {
        throw new IllegalArgumentException("unsupported drawable type");
    }
}

Luego tienes que agregar en tu archivo gradle:

android {
    defaultConfig {
        vectorDrawables.useSupportLibrary = true
    }
}

En pre-Lollipop usará VectorDrawableCompat y en Lollipop usará VectorDrawable.

EDITAR

He editado la condición siguiendo el comentario de @user3109468

 19
Author: Eselfar,
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-03-27 16:34:01

Felicitaciones a @Alexey

Aquí está la versión Kotlin usando extensiones para Context

fun Context.getBitmapFromVectorDrawable(drawableId: Int): Bitmap? {
    var drawable = ContextCompat.getDrawable(this, drawableId) ?: return null

    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
        drawable = DrawableCompat.wrap(drawable).mutate()
    }

    val bitmap = Bitmap.createBitmap(
            drawable.intrinsicWidth,
            drawable.intrinsicHeight,
            Bitmap.Config.ARGB_8888) ?: return null
    val canvas = Canvas(bitmap)
    drawable.setBounds(0, 0, canvas.width, canvas.height)
    drawable.draw(canvas)

    return bitmap
}

Ejemplo de uso en Activity:

val bitmap = this.getBitmapFromVectorDrawable(R.drawable.ic_done_white_24dp)
 3
Author: Gunhan,
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-04-18 14:52:00

Si estás dispuesto a usar Android KTX para Kotlin puedes usar el método de extensión Drawable#toBitmap() para lograr el mismo efecto que las otras respuestas:

val bitmap = AppCompatResources.getDrawable(requireContext(), drawableId).toBitmap() 

O

val bitmap = AppCompatResources.getDrawable(context, drawableId).toBitmap() 

Para agregar este y otros métodos de extensión útiles, deberá agregar lo siguiente a su nivel de módulo build.gradle

repositories {
    google()
}

dependencies {
    implementation 'androidx.core:core-ktx:1.0.0-alpha1'
}

Enlace a la fuente del método de extensión aquí.

Tenga en cuenta que esto funcionará para cualquier subclase de Drawable y si el Drawable es un BitmapDrawable lo hará acceso directo para usar el Bitmap subyacente.

 3
Author: David Rawson,
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-08 08:35:52
Drawable layerDrawable = (Drawable) imageBase.getDrawable();
Bitmap bitmap = Bitmap.createBitmap(layerDrawable.getIntrinsicWidth(),
        layerDrawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
layerDrawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
layerDrawable.draw(canvas);

ImageTeste.setImageBitmap (addGradient (bitmap));

 0
Author: Amine,
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-02-03 13:28:50