web-dev-qa-db-fra.com

AppCompat 23.2 utilise VectorDrawableCompat avec RemoteViews (AppWidget) sur API <21

J'ai un AppWidget et j'aimerais également utiliser VectorDrawables sur des appareils pré-Lollipop. VectorDrawableCompat ne fonctionnera pas avec les RemoteViews que je crée.

Pour réduire la taille de l'APK de mon application, je ne veux pas ajouter d'autres versions PNG de mes drawables pour les anciennes plates-formes d'API.

Comment puis je faire ça?

29
araks

MISE À JOUR 22/10/2017

Comme indiqué par @ user924 maintenant l'accès AppCompatDrawableManager est limité à sa propre bibliothèque. ContextCompat.getDrawable (...) devrait faire l'affaire.

MISE À JOUR 05/09/2016

Comme indiqué par @ kirill-kulakov dans sa réponse, les dernières mises à jour de la bibliothèque de support limitaient la visibilité de TintContextWrapper à son propre package. Je mets à jour ma réponse pour supprimer le code incorrect, mais merci à Kirill pour la correction!

VectorDrawable et RemoteViews pré-Lollipop

Vous pouvez éviter d'ajouter des versions tramées alternatives de vos ressources vectorielles dessinables avec un hack simple : utilisez AppCompat TintResources à TintContextWrapper en utilisant AppCompatDrawableManager  en utilisant ContextCompat .

TintResources AppCompatDrawableManager   ContextCompat est la classe qui, entre autres, sur les appareils pré-Lollipop, analyse les fichiers XML VectorDrawable et les convertit en Instances VectorDrawableCompat pouvant être utilisées jusqu'à l'API 7.

Ensuite, une fois que vous avez une instance VectorDrawableCompat , pixellisez-la sur un bitmap. Vous utiliserez plus tard ce bitmap dans une ImageView distante .


Avant de commencer: bibliothèque AppCompat

Assurez-vous que vous utilisez Android Studio 2.0+ et que vous avez configuré votre application build.gradle comme suit:

Android {
  defaultConfig {
    vectorDrawables.useSupportLibrary = true
  }
}

dependencies {
  compile 'com.Android.support:appcompat-v7:23.3.0'
}


Mettez à jour votre AppWidgetProvider

Tout d'abord: ne définissez pas vos ressources vectorielles dessinables dans votre fichier de mise en page RemoteViews (ni Android:src ni app:srcCompat marchera). Vous devrez les définir par programme.

Dans votre classe AppWidgetProvider , définissez la ressource vectorielle ou une version tramée en fonction du niveau de l'API:

RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.appwidget_layout);

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Lollipop) {
  remoteViews.setImageViewResource(R.id.imageView, R.drawable.vector);

} else {
  Drawable d = ContextCompat.getDrawable(context, R.drawable.vector);
  Bitmap b = Bitmap.createBitmap(d.getIntrinsicWidth(),
                                 d.getIntrinsicHeight(),
                                 Bitmap.Config.ARGB_8888);
  Canvas c = new Canvas(b);
  d.setBounds(0, 0, c.getWidth(), c.getHeight());
  d.draw(c);
  remoteViews.setImageViewBitmap(R.id.imageView, b);
}


Les références

51
araks

La méthode suivante convertira le vector drawable à un bitmap avant, cela devrait faire l'affaire.

public static BitmapDrawable vectorToBitmapDrawable(Context ctx, @DrawableRes int resVector) {
    return new BitmapDrawable(ctx.getResources(), vectorToBitmap(ctx, resVector));
}

public static Bitmap vectorToBitmap(Context ctx, @DrawableRes int resVector) {
    Drawable drawable = AppCompatDrawableManager.get().getDrawable(ctx, resVector);
    Bitmap b = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
    Canvas c = new Canvas(b);
    drawable.setBounds(0, 0, c.getWidth(), c.getHeight());
    drawable.draw(c);
    return b;
}
8
Kirill Kulakov