155 votes

Convertir une vue en Bitmap sans l'afficher dans Android ?

Je vais essayer d'expliquer ce que je dois faire exactement.

J'ai 3 écrans distincts appelés A,B,C. Il y a un autre écran appelé HomeScreen où tous les 3 écrans bitmap doivent être affichés dans la vue Galerie et l'utilisateur peut sélectionner dans quelle vue il veut aller.

J'ai réussi à obtenir les Bitmaps des 3 écrans et à les afficher dans la vue Galerie en plaçant tout le code dans l'activité HomeScreen uniquement. Maintenant, cela a beaucoup compliqué le code et je voudrais le simplifier.

Puis-je appeler une autre activité à partir de l'écran d'accueil, ne pas l'afficher et obtenir simplement le bitmap de cet écran ? Par exemple, disons que je viens d'appeler HomeScreen et qu'il appelle l'activité A,B,C et qu'aucune des activités de A,B,C n'est affichée. On obtient simplement le bitmap de cet écran par getDrawingCache(). Ensuite, nous pouvons afficher ces bitmaps dans la vue Galerie de l'écran d'accueil.

J'espère avoir expliqué le problème très clairement.

Veuillez me faire savoir si cela est réellement possible.

1 votes

Je ne suis pas tout à fait sûr, mais je pense que vous ne pourrez pas le faire. Le problème est que les activités sont destinées à être affichées à l'utilisateur. Vous pouvez lancer l'activité puis la masquer immédiatement, mais l'activité sera toujours visible pour l'utilisateur pendant une fraction de seconde. Elle est affichée suffisamment longtemps pour être remarquée. Le fait que l'écran scintille plusieurs fois donne à l'application un aspect peu professionnel. Cependant, il est possible qu'il existe une commande permettant de démarrer une activité sans l'afficher ; je ne connais pas cette commande si elle existe.

6 votes

En fait, j'ai pu le faire.

0 votes

Oh, comment pouvez-vous appeler cette activité mais ne pas la montrer ? Puis-je prendre la mise en page de l'activité actuelle comme modèle pour générer des bitmaps tout en lui fournissant un contenu différent ?

239voto

Sponge Points 2812

Il existe un moyen de le faire. Vous devez créer un Bitmap et un Canvas et appeler view.draw(canvas) ;

Voici le code :

public static Bitmap loadBitmapFromView(View v) {
    Bitmap b = Bitmap.createBitmap( v.getLayoutParams().width, v.getLayoutParams().height, Bitmap.Config.ARGB_8888);                
    Canvas c = new Canvas(b);
    v.layout(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
    v.draw(c);
    return b;
}

si la vue n'a pas été affichée avant, sa taille sera de zéro. Il est possible de la mesurer comme ceci :

if (v.getMeasuredHeight() <= 0) {
    v.measure(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
    Bitmap b = Bitmap.createBitmap(v.getMeasuredWidth(), v.getMeasuredHeight(), Bitmap.Config.ARGB_8888);
    Canvas c = new Canvas(b);
    v.layout(0, 0, v.getMeasuredWidth(), v.getMeasuredHeight());
    v.draw(c);
    return b;
}

EDIT : selon ce poste , _Passing WRAP_CONTENT comme valeur pour makeMeasureSpec() ne fait pas de bien_ (bien que pour certaines classes de vues cela fonctionne), et la méthode recommandée est :

// Either this
int specWidth = MeasureSpec.makeMeasureSpec(parentWidth, MeasureSpec.AT_MOST);
// Or this
int specWidth = MeasureSpec.makeMeasureSpec(0 /* any */, MeasureSpec.UNSPECIFIED);
view.measure(specWidth, specWidth);
int questionWidth = view.getMeasuredWidth();

1 votes

J'ai essayé mais tout ce que j'ai obtenu est une boîte noire semi-transparente. Dois-je faire quelque chose sur la vue pour qu'elle soit prête à être dessinée en bitmap ?

4 votes

En fait, j'ai dû changer cela en v.layout(v.getLeft(), v.getTop(), v.getRight(), v.getBottom()); pour que cela fonctionne correctement, mais merci pour le code :)

4 votes

J'ai dû utiliser v.getWidth() au lieu de v.getLayoutParams().width et de même pour la hauteur. Sinon, cela fonctionne maintenant.

36voto

Gil SH Points 706

Voici ma solution :

public static Bitmap getBitmapFromView(View view) {
    Bitmap returnedBitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(),Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(returnedBitmap);
    Drawable bgDrawable =view.getBackground();
    if (bgDrawable!=null) 
        bgDrawable.draw(canvas);
    else 
        canvas.drawColor(Color.WHITE);
    view.draw(canvas);
    return returnedBitmap;
}

Profitez-en :)

0 votes

Merci. J'avais des problèmes sur certains appareils si la hauteur dépassait une certaine valeur. Je n'ai pas encore tout testé mais cela semble résoudre le problème.

0 votes

Merci, ça m'a aidé.

30voto

levigroker Points 309

Je sais qu'il s'agit peut-être d'un problème dépassé, mais j'ai eu des difficultés à faire fonctionner l'une de ces solutions pour moi. Plus précisément, j'ai constaté que si des modifications étaient apportées à la vue après qu'elle ait été gonflée, ces modifications n'étaient pas incorporées dans le bitmap rendu.

Voici la méthode qui a fini par fonctionner dans mon cas. Avec une mise en garde, cependant. avant d'appeler getViewBitmap(View) J'ai gonflé ma vue et lui ai demandé de faire une mise en page avec des dimensions connues. C'était nécessaire car la mise en page de ma vue n'avait aucune hauteur/largeur jusqu'à ce que le contenu soit placé à l'intérieur.

View view = LayoutInflater.from(context).inflate(layoutID, null);
//Do some stuff to the view, like add an ImageView, etc.
view.layout(0, 0, width, height);

Bitmap getViewBitmap(View view)
{
    //Get the dimensions of the view so we can re-layout the view at its current size
    //and create a bitmap of the same size 
    int width = view.getWidth();
    int height = view.getHeight();

    int measuredWidth = View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY);
    int measuredHeight = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY);

    //Cause the view to re-layout
    view.measure(measuredWidth, measuredHeight);
    view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());

    //Create a bitmap backed Canvas to draw the view into
    Bitmap b = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
    Canvas c = new Canvas(b);

    //Now that the view is laid out and we have a canvas, ask the view to draw itself into the canvas
    view.draw(c);

    return b;
}

La "sauce magique" pour moi a été trouvée ici : https://groups.google.com/forum/#!topic/Android-developers/BxIBAOeTA1Q

A la vôtre,

Levi

0 votes

A la vôtre ! Il semble que l'on doive appeler measure et requestLayout après toute modification de la mise en page pour qu'ils soient affichés.

1 votes

Merci pour cette solution ! J'avais le même problème. J'utilisais measure() y layout() avant de remplir ma vue, j'ai eu des résultats étranges. En déplaçant ces appels vers le bas, au-dessus de createBitmap() l'a réparé pour moi !

24voto

Dwivedi Ji Points 2895

Essayez ça,

/**
 * Draw the view into a bitmap.
 */
public static Bitmap getViewBitmap(View v) {
    v.clearFocus();
    v.setPressed(false);

    boolean willNotCache = v.willNotCacheDrawing();
    v.setWillNotCacheDrawing(false);

    // Reset the drawing cache background color to fully transparent
    // for the duration of this operation
    int color = v.getDrawingCacheBackgroundColor();
    v.setDrawingCacheBackgroundColor(0);

    if (color != 0) {
        v.destroyDrawingCache();
    }
    v.buildDrawingCache();
    Bitmap cacheBitmap = v.getDrawingCache();
    if (cacheBitmap == null) {
        Log.e(TAG, "failed getViewBitmap(" + v + ")", new RuntimeException());
        return null;
    }

    Bitmap bitmap = Bitmap.createBitmap(cacheBitmap);

    // Restore the view
    v.destroyDrawingCache();
    v.setWillNotCacheDrawing(willNotCache);
    v.setDrawingCacheBackgroundColor(color);

    return bitmap;
}

0 votes

Comment l'utiliser à partir de ma classe d'activité principale ?

1 votes

Cette fonction est obsolète

21voto

a.ch. Points 4560

Il existe une excellente fonction d'extension Kotlin dans Android KTX : View.drawToBitmap(Bitmap.Config)

19 votes

Cela ne fonctionnera pas si la vue n'est pas présentée dans la mise en page. Erreur : "IllegalStateException : La vue doit être présentée avant d'appeler drawToBitmap()"

0 votes

Facile et simple. Merci frère

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X