Eine Ansicht in Bitmap konvertieren, ohne sie in Android anzuzeigen?

133

Ich werde versuchen zu erklären, was genau ich tun muss.

Ich habe 3 separate Bildschirme, sagen A, B, C. Es gibt einen weiteren Bildschirm namens say HomeScreen, auf dem alle 3 Bildschirm-Bitmaps in der Galerieansicht angezeigt werden sollen und der Benutzer auswählen kann, in welche Ansicht er gehen möchte.

Ich konnte die Bitmaps aller 3 Bildschirme abrufen und in der Galerieansicht anzeigen, indem ich den gesamten Code nur in der HomeScreen-Aktivität platzierte. Dies hat den Code sehr kompliziert gemacht und ich möchte ihn vereinfachen.

Kann ich also eine andere Aktivität von HomeScreen aus aufrufen und nicht anzeigen und nur die Bitmap dieses Bildschirms abrufen? Angenommen, ich rufe nur HomeScreen auf und es werden die Aktivitäten A, B, C aufgerufen, und keine der Aktivitäten von A, B, C wird angezeigt. Es gibt nur die Bitmap dieses Bildschirms von getDrawingCache (). Und dann können wir diese Bitmaps in der Galerieansicht in HomeScreen anzeigen.

Ich hoffe, ich habe das Problem sehr klar erklärt.

Bitte lassen Sie mich wissen, ob dies tatsächlich möglich ist.

sunil
quelle
1
Ich bin mir nicht ganz sicher, aber ich denke, Sie werden das nicht können. Das Problem ist, dass Aktivitäten dem Benutzer angezeigt werden sollen. Sie können die Aktivität starten und dann sofort ausblenden, aber die Aktivität ist für den Benutzer für den Bruchteil einer Sekunde weiterhin sichtbar. Es wird lange genug angezeigt, um bemerkt zu werden. Wenn der Bildschirm mehrmals flackert, sieht die App unprofessionell aus. Möglicherweise gibt es jedoch einen Befehl zum Starten einer Aktivität, ohne sie anzuzeigen. Ich weiß nur nicht, ob es existiert.
Steve Haley
5
Eigentlich konnte ich das machen.
Sunil
Oh, wie können Sie diese Aktivität aufrufen, aber nicht anzeigen? Kann ich das Layout der aktuellen Aktivität als Vorlage verwenden, um eine Bitmap zu generieren, während verschiedene Inhalte zugeführt werden?
Zionpi
Überprüfen Sie die Antwort in diesem Beitrag, ich habe eine Lösung gefunden: stackoverflow.com/questions/36424381/…
Wackaloon

Antworten:

212

Es gibt einen Weg, dies zu tun. Sie müssen eine Bitmap und eine Leinwand erstellen und view.draw (Zeichenfläche) aufrufen.

Hier ist der 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;
}

Wenn die Ansicht nicht vor der Größe angezeigt wurde, ist sie Null. Es ist möglich, es so zu messen:

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

BEARBEITEN: Laut diesem Beitrag ist das Übergeben WRAP_CONTENTals Wert an makeMeasureSpec()nichts Gutes (obwohl es für einige Ansichtsklassen funktioniert). Die empfohlene Methode lautet:

// 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();
Simon
quelle
1
Ich habe es versucht, aber alles, was ich bekomme, ist eine halbtransparente Blackbox. Muss ich in der Ansicht etwas tun, um sie für das Zeichnen von Bitmaps vorzubereiten?
Bobbake4
4
Ich musste dies tatsächlich ändern v.layout(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());, damit es richtig funktioniert, aber danke für den Code :)
Triade
3
Ich musste v.getWidth () anstelle von v.getLayoutParams () verwenden. Width und ähnliches für height. Ansonsten funktioniert jetzt.
David Manpearl
1
Ich habe benutzt v.measure(0, 0); v.getMeasuredWidth(); v.getMeasuredHeight();.
Brais Gabin
7
Bitmap b = Bitmap.createBitmap(v.getWidth(), v.getHeight(), Bitmap.Config.ARGB_8888);Funktioniert besser
Pierre
29

Hier ist meine Lösung:

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

Genießen :)

Gil SH
quelle
Vielen Dank. Bei einigen Geräten hatte ich Probleme, wenn die Höhe einen bestimmten Wert überschritt. Ich habe nicht vollständig getestet, aber dies scheint das zu beheben.
BMF
22

Versuche dies,

/**
 * 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;
}
Dwivedi Ji
quelle
Wie verwende ich es aus meiner Hauptaktivitätsklasse?
Si8
Dies ist veraltet
Ch Vas
20

Ich weiß, dass dies ein veraltetes Problem sein kann, aber ich hatte Probleme, eine dieser Lösungen für mich zum Laufen zu bringen. Insbesondere stellte ich fest, dass Änderungen an der Ansicht nach dem Aufblasen nicht in die gerenderte Bitmap übernommen werden.

Hier ist die Methode, die für meinen Fall funktioniert hat. Mit einer Einschränkung jedoch. Vor dem Anruf habe getViewBitmap(View)ich meine Ansicht aufgeblasen und sie gebeten, mit bekannten Abmessungen zu gestalten. Dies war erforderlich, da mein Ansichtslayout die Höhe / Breite auf Null setzen würde, bis der Inhalt darin platziert wurde.

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

Die "magische Sauce" für mich wurde hier gefunden: https://groups.google.com/forum/#!topic/android-developers/BxIBAOeTA1Q

Prost,

Levi

Levigroker
quelle
Prost! Es scheint, dass man Measure and RequestLayout nach Änderungen am Layout aufrufen muss, damit sie angezeigt werden
TheIT
1
Danke für diese Lösung! Ich hatte das gleiche Problem. Ich benutzte measure()und layout()bevor ich meine Ansicht füllte, hatte ich seltsame Ergebnisse. Das Verschieben dieser Anrufe nach oben hat createBitmap()es für mich behoben!
Sven Jacobs
6

In Android KTX gibt es eine großartige Kotlin-Erweiterungsfunktion: View.drawToBitmap(Bitmap.Config)

a.ch.
quelle
3
Dies funktioniert nicht, wenn die Ansicht nicht im Layout angezeigt wird. Fehler: "IllegalStateException: Die Ansicht muss vor dem Aufruf von drawToBitmap () angelegt werden"
Val
2

Hoffe das hilft

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

Die Aktualisierungsmethode
getDrawingCache() ist in API-Ebene 28 veraltet. Suchen Sie daher nach einer anderen Alternative für API-Ebene> 28.

Akhilesh Kumar
quelle
1
getDrawingCacheist derzeit veraltet.
David Miguel
0

Ich finde das etwas besser:

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

Mit dem obigen Code müssen Sie die Größe der Bitmap nicht angeben (verwenden Sie 0 für Breite und Höhe), wenn Sie die der Ansicht selbst verwenden möchten.

Wenn Sie spezielle Ansichten (z. B. SurfaceView, Surface oder Window) in eine Bitmap konvertieren möchten, sollten Sie stattdessen die PixelCopy- Klasse verwenden. Es erfordert jedoch API 24 und höher. Ich weiß vorher nicht, wie ich es machen soll.

Android-Entwickler
quelle
Jede Idee, keine TextView wird in Bitmap hinzugefügt. Es werden nur ImageViews hinzugefügt.
Khemraj
@ Khemraj Ich verstehe die Frage nicht.
Android-Entwickler
Es war meine Schuld, dass mein TextView nicht in der Bitmap vorhanden war. Da ich ein helles Farbthema angewendet hatte, danke für die Antwort.
Khemraj
1
@ Khemraj Sorry, aber ich verstehe immer noch nicht. Alles in Ordnung jetzt?
Android-Entwickler
Ja Bruder, ich weiß nicht warum du mich nicht kriegst :). Ich hatte eine Textansicht im Layout, die ich in Bitmap konvertieren wollte. Das Layout hatte eine ImageView und eine TextView. ImageView wurde in Bitmap konvertiert. TextView wurde jedoch nicht in Bitmap angezeigt. Das war ein Problem. Danach wurde mir klar, dass ich ein Thema angewendet hatte, das TextView-Text weiß färbte. Ich habe es repariert. Und jetzt alles in Ordnung. Vielen Dank.
Khemraj
0

Layout oder Ansicht zur 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;
}

Aufrufmethode:

Bitmap src = createBitmapFromLayout(View.inflate(this, R.layout.sample, null)/* or pass your view object*/);
Shyam Kumar
quelle
-3
view.setDrawingCacheEnabled(true);
Bitmap bitmap = Bitmap.createBitmap(view.getDrawingCache());
view.setDrawingCacheEnabled(false);
Ashutosh Gupta
quelle
Bitte erläutern Sie, was dies bewirkt.
Paul Floyd