Convertire una vista in Bitmap senza visualizzarla in Android?


133

Proverò a spiegare cosa devo fare esattamente.

Ho 3 schermi separati dire A, B, C. C'è un'altra schermata chiamata diciamo HomeScreen in cui tutte e 3 le bitmap dovrebbero essere visualizzate nella vista Galleria e l'utente può selezionare in quale vista vuole andare.

Sono stato in grado di ottenere le bitmap di tutte e 3 le schermate e visualizzarle nella vista Galleria posizionando tutto il codice solo nell'attività HomeScreen. Ora, questo ha complicato molto il codice e mi piacerebbe semplificarlo.

Quindi, posso chiamare un'altra attività da HomeScreen e non visualizzarla e ottenere semplicemente la bitmap di quella schermata. Ad esempio, supponiamo che io abbia appena chiamato HomeScreen e che chiama Attività A, B, C e nessuna delle attività da A, B, C sia visualizzata. Fornisce semplicemente la bitmap di quella schermata tramite getDrawingCache (). E quindi possiamo visualizzare quelle bitmap nella vista Galleria in HomeScreen.

Spero di aver spiegato il problema molto chiaramente.

Per favore fatemi sapere se questo è effettivamente possibile.


1
Non ne sono del tutto sicuro, ma penso che non sarai in grado di farlo. Il problema è che le attività devono essere visualizzate all'utente. È possibile avviare l'attività e nasconderla immediatamente, ma l'attività sarà comunque visibile all'utente per una frazione di secondo. Viene mostrato abbastanza a lungo per essere notato, quindi avere lo sfarfallio dello schermo più volte rende l'app non professionale. Tuttavia, potrebbe essere possibile che esista un comando per avviare un'attività senza visualizzarla; Semplicemente non ne conosco uno se esiste.
Steve Haley,

5
In realtà, sono stato in grado di farlo.
domenica

Oh, come puoi chiamare quell'attività ma non mostrarla? Posso prendere il layout dell'attività corrente come modello per generare bitmap mentre alimento contenuti diversi?
zionpi,

Controllare la risposta in questo post, ho trovato qualche tipo di soluzione: stackoverflow.com/questions/36424381/...
Wackaloon

Risposte:


213

c'è un modo per farlo. devi creare una bitmap e una tela e chiamare view.draw (tela);

ecco il codice:

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

se la vista non è stata visualizzata prima della dimensione sarà zero. È possibile misurarlo in questo modo:

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: secondo questo post , Passare WRAP_CONTENTcome valore a makeMeasureSpec()non fa nulla di buono (anche se per alcune classi di visualizzazione funziona) e il metodo consigliato è:

// 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
Ho provato questo, ma tutto quello che ottengo è una scatola nera semi trasparente. Devo fare qualcosa sulla vista per prepararlo per il disegno bitmap?
Bobbake4,

4
In realtà ho dovuto cambiarlo v.layout(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());per farlo funzionare correttamente, ma grazie per il codice :)
triade

3
Ho dovuto usare v.getWidth () invece di v.getLayoutParams (). Width e simili per altezza. Altrimenti, ora funziona.
David Manpearl,

1
Ho usato v.measure(0, 0); v.getMeasuredWidth(); v.getMeasuredHeight();.
Brais Gabin,

7
Bitmap b = Bitmap.createBitmap(v.getWidth(), v.getHeight(), Bitmap.Config.ARGB_8888);Funziona meglio
Pierre,

29

ecco la mia soluzione:

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

Godere :)


Grazie. Ho avuto problemi su alcuni dispositivi se l'altezza era oltre un certo valore. Non ho testato completamente, ma questo sembra risolverlo.
BMF,

22

Prova questo,

/**
 * 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;
}

Come lo uso dalla mia classe di attività principale?
Si8,

Questo è deprecato
Ch Vas

20

So che questo potrebbe essere un problema obsoleto, ma ho avuto problemi a far funzionare una di queste soluzioni per me. In particolare, ho scoperto che se fossero state apportate modifiche alla vista dopo che era stata gonfiata, tali modifiche non sarebbero state incorporate nella bitmap renderizzata.

Ecco il metodo che ha finito per funzionare per il mio caso. Con un avvertimento, tuttavia. prima di chiamare getViewBitmap(View)ho gonfiato la mia vista e ho chiesto di layout con dimensioni note. Ciò era necessario poiché il layout della mia vista lo avrebbe portato a zero altezza / larghezza fino a quando il contenuto non veniva inserito all'interno.

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 "salsa magica" per me è stata trovata qui: https://groups.google.com/forum/#!topic/android-developers/BxIBAOeTA1Q

Saluti,

Levi


Saluti! Sembra che si debbano chiamare misure e requestLayout dopo ogni modifica al layout per poterle visualizzare
TheIT

1
Grazie per questa soluzione! Ho avuto lo stesso problema. Stavo usando measure()e layout()prima di popolare la mia vista così ho avuto strani risultati. Spostare queste chiamate verso il basso, sopra createBitmap()risolto per me!
Sven Jacobs,

6

C'è una grande funzione di estensione Kotlin in Android KTX: View.drawToBitmap(Bitmap.Config)


3
Questo non funzionerà se la vista non è presentata nel layout. Errore: "IllegalStateException: la vista deve essere strutturata prima di chiamare drawToBitmap ()"
Val

2

Spero che questo ti aiuti

View view="some view instance";        
view.setDrawingCacheEnabled(true);
Bitmap bitmap=view.getDrawingCache();
view.setDrawingCacheEnabled(false);

Il
getDrawingCache() metodo di aggiornamento è obsoleto nel livello API 28. Quindi cerca un'altra alternativa per il livello API> 28.


1
getDrawingCacheè attualmente obsoleto.
David Miguel,

1

Layout o vista su bitmap:

 private Bitmap createBitmapFromLayout(View tv) {      
    int spec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
    tv.measure(spec, spec);
    tv.layout(0, 0, tv.getMeasuredWidth(), tv.getMeasuredHeight());
    Bitmap b = Bitmap.createBitmap(tv.getMeasuredWidth(), tv.getMeasuredWidth(),
            Bitmap.Config.ARGB_8888);
    Canvas c = new Canvas(b);
    c.translate((-tv.getScrollX()), (-tv.getScrollY()));
    tv.draw(c);
    return b;
}

Metodo di chiamata:

Bitmap src = createBitmapFromLayout(View.inflate(this, R.layout.sample, null)/* or pass your view object*/);

0

Penso che sia un po 'meglio:

/**
 * draws the view's content to a bitmap. code initially based on :
 * http://nadavfima.com/android-snippet-inflate-a-layout-draw-to-a-bitmap/
 */
@Nullable
public static Bitmap drawToBitmap(final View viewToDrawFrom, int width, int height) {
    boolean wasDrawingCacheEnabled = viewToDrawFrom.isDrawingCacheEnabled();
    if (!wasDrawingCacheEnabled)
        viewToDrawFrom.setDrawingCacheEnabled(true);
    if (width <= 0 || height <= 0) {
        if (viewToDrawFrom.getWidth() <= 0 || viewToDrawFrom.getHeight() <= 0) {
            viewToDrawFrom.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
            width = viewToDrawFrom.getMeasuredWidth();
            height = viewToDrawFrom.getMeasuredHeight();
        }
        if (width <= 0 || height <= 0) {
            final Bitmap bmp = viewToDrawFrom.getDrawingCache();
            final Bitmap result = bmp == null ? null : Bitmap.createBitmap(bmp);
            if (!wasDrawingCacheEnabled)
                viewToDrawFrom.setDrawingCacheEnabled(false);
            return result;
        }
        viewToDrawFrom.layout(0, 0, width, height);
    } else {
        viewToDrawFrom.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
        viewToDrawFrom.layout(0, 0, viewToDrawFrom.getMeasuredWidth(), viewToDrawFrom.getMeasuredHeight());
    }
    final Bitmap drawingCache = viewToDrawFrom.getDrawingCache();
    final Bitmap bmp = ThumbnailUtils.extractThumbnail(drawingCache, width, height);
    final Bitmap result = bmp == null || bmp != drawingCache ? bmp : Bitmap.createBitmap(bmp);
    if (!wasDrawingCacheEnabled)
        viewToDrawFrom.setDrawingCacheEnabled(false);
    return result;
}

Utilizzando il codice sopra, non è necessario specificare la dimensione della bitmap (utilizzare 0 per larghezza e altezza) se si desidera utilizzare quello della vista stessa.

Inoltre, se desideri convertire viste speciali (SurfaceView, Surface o Window, ad esempio) in una bitmap, dovresti invece utilizzare la classe PixelCopy . Richiede API 24 e successive. Non so come farlo prima.


Qualsiasi idea, nessun TextView viene aggiunto in bitmap. Vengono aggiunte solo le visualizzazioni immagini.
Khemraj,

@Khemraj Non capisco la domanda.
sviluppatore Android

È stata colpa mia se il mio TextView non era presente in bitmap. Perché avevo applicato un tema di colore chiaro, grazie per la risposta.
Khemraj,

1
@Khemraj Scusa ma ancora non capisco. Va tutto bene adesso?
sviluppatore Android il

Sì fratello, non so perché non mi stai prendendo :). Avevo un TextView nel layout che volevo convertire in Bitmap. Il layout aveva un ImageView e un TextView. ImageView veniva convertito in Bitmap. Ma TextView non appariva in Bitmap. Questo era un problema. Dopo di che mi sono reso conto di aver applicato un tema che rendeva il testo di TextView bianco. L'ho riparato. E tutto ok adesso. Grazie.
Khemraj,

-3
view.setDrawingCacheEnabled(true);
Bitmap bitmap = Bitmap.createBitmap(view.getDrawingCache());
view.setDrawingCacheEnabled(false);

Per favore, spiega cosa fa questo.
Paul Floyd,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.