Mengonversi tampilan ke Bitmap tanpa menampilkannya di Android?

133

Saya akan mencoba menjelaskan apa yang harus saya lakukan.

Saya memiliki 3 layar terpisah yang mengatakan A, B, C. Ada layar lain yang disebut say HomeScreen di mana semua 3 layar bitmap harus ditampilkan dalam tampilan Galeri dan pengguna dapat memilih tampilan mana yang ingin ia tuju.

Saya sudah bisa mendapatkan Bitmap dari semua 3 layar dan menampilkannya dalam tampilan Galeri dengan menempatkan semua kode dalam Kegiatan HomeScreen saja. Sekarang, kode ini sangat rumit dan saya ingin menyederhanakannya.

Jadi, bisakah saya memanggil Aktivitas lain dari HomeScreen dan tidak menampilkannya dan hanya mendapatkan Bitmap dari layar itu. Sebagai contoh, katakan saya hanya memanggil HomeScreen dan itu memanggil Aktivitas A, B, C dan tidak ada Kegiatan dari A, B, C yang ditampilkan. Itu hanya memberikan Bitmap dari layar itu dengan getDrawingCache (). Dan kemudian kita bisa menampilkan bitmap itu dalam tampilan Galeri di Layar Beranda.

Saya harap saya telah menjelaskan masalahnya dengan sangat jelas.

Tolong beri tahu saya jika ini benar-benar mungkin.

sunil
sumber
1
Saya tidak sepenuhnya yakin, tetapi saya pikir Anda tidak akan bisa melakukan itu. Masalahnya adalah bahwa kegiatan dimaksudkan untuk ditampilkan kepada pengguna. Anda dapat memulai aktivitas dan kemudian segera menyembunyikannya, tetapi aktivitas tersebut akan tetap terlihat oleh pengguna selama sepersekian detik. Ini ditampilkan cukup lama untuk diperhatikan sehingga memiliki layar berkedip beberapa kali membuat aplikasi terlihat tidak profesional. Namun, ada kemungkinan bahwa ada perintah untuk memulai suatu kegiatan tanpa menampilkannya; Saya hanya tidak tahu jika ada.
Steve Haley
5
Sebenarnya, saya bisa melakukan ini.
sunil
Oh, bagaimana Anda bisa menyebut aktivitas itu tetapi tidak menunjukkannya? Dapatkah saya menggunakan tata letak aktivitas saat ini sebagai templat untuk menghasilkan bitmap sambil mengumpankan konten yang berbeda ke dalamnya?
zionpi
Periksa jawaban di posting ini, saya menemukan beberapa solusi: stackoverflow.com/questions/36424381/…
Wackaloon

Jawaban:

213

ada cara untuk melakukan ini. Anda harus membuat Bitmap dan Canvas dan memanggil view.draw (canvas);

ini kodenya:

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

jika tampilan tidak ditampilkan sebelum ukurannya akan menjadi nol. Mungkin untuk mengukurnya seperti ini:

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: sesuai dengan posting ini , Melewati WRAP_CONTENTsebagai nilai untuk makeMeasureSpec()tidak melakukan hal yang baik (walaupun untuk beberapa kelas tampilan itu berfungsi), dan metode yang disarankan adalah:

// 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
sumber
1
Saya mencoba ini, tetapi yang saya dapatkan hanyalah kotak hitam semi transparan. Apakah saya perlu melakukan sesuatu pada tampilan untuk membuatnya siap untuk menggambar bitmap?
Bobbake4
4
Saya benar-benar harus mengubah ini agar v.layout(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());ini berfungsi dengan benar, tapi terima kasih untuk kodenya :)
triad
3
Saya harus menggunakan v.getWidth () alih-alih v.getLayoutParams (). Lebar dan serupa untuk ketinggian. Kalau tidak, sekarang bekerja.
David Manpearl
1
Saya menggunakan v.measure(0, 0); v.getMeasuredWidth(); v.getMeasuredHeight();.
Brais Gabin
7
Bitmap b = Bitmap.createBitmap(v.getWidth(), v.getHeight(), Bitmap.Config.ARGB_8888);Bekerja lebih baik
Pierre
29

inilah solusi saya:

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

Nikmati :)

Gil SH
sumber
Terima kasih. Saya mengalami masalah pada beberapa perangkat jika ketinggiannya melebihi nilai tertentu. Saya belum menguji sepenuhnya tetapi ini tampaknya menyelesaikan itu.
BMF
22

Coba ini,

/**
 * 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
sumber
Bagaimana saya menggunakannya dari kelas aktivitas Utama saya?
Si8
Ini sudah ditinggalkan
Ch Vas
20

Saya tahu ini mungkin masalah basi, tetapi saya mengalami masalah dalam membuat solusi ini bekerja untuk saya. Secara khusus, saya menemukan bahwa jika ada perubahan yang dilakukan pada tampilan setelah digelembungkan bahwa perubahan itu tidak akan dimasukkan ke dalam bitmap yang diberikan.

Inilah metode yang akhirnya berhasil untuk kasus saya. Namun, dengan satu peringatan. sebelum menelepon getViewBitmap(View)saya meningkatkan pandangan saya dan memintanya untuk tata letak dengan dimensi yang diketahui. Ini diperlukan karena tata letak tampilan saya akan membuatnya nol tinggi / lebar sampai konten ditempatkan di dalam.

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

"Saus ajaib" untuk saya ditemukan di sini: https://groups.google.com/forum/#!topic/android-developers/BxIBAOeTA1Q

Bersulang,

Retribusi

levigroker
sumber
Bersulang! Tampaknya seseorang harus memanggil ukuran dan memintaLayout setelah perubahan tata letak agar ditampilkan
TheIT
1
Terima kasih atas solusi ini! Saya memiliki masalah yang sama. Saya menggunakan measure()dan layout()sebelum saya mengisi pandangan saya jadi saya punya hasil yang aneh. Memindahkan panggilan-panggilan ini ke bawah, createBitmap()tetap memperbaiki untuk saya!
Sven Jacobs
6

Ada fungsi ekstensi Kotlin yang hebat di Android KTX: View.drawToBitmap(Bitmap.Config)

a.ch.
sumber
3
Ini tidak akan berfungsi jika tampilan tidak disajikan dalam tata letak. Kesalahan: "IllegalStateException: Lihat perlu ditata sebelum memanggil drawToBitmap ()"
Val
2

Semoga ini membantu

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


getDrawingCache()Metode pembaruan sudah tidak digunakan lagi di API level 28. Jadi cari alternatif lain untuk level API> 28.

Akhilesh Kumar
sumber
1
getDrawingCachesaat ini sudah tidak digunakan lagi.
David Miguel
1

Layout atau view to 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;
}

Metode Panggilan:

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

Saya pikir ini sedikit lebih baik:

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

Menggunakan kode di atas, Anda tidak perlu menentukan ukuran bitmap (gunakan 0 untuk lebar & tinggi) jika Anda ingin menggunakan salah satu tampilan itu sendiri.

Juga, jika Anda ingin mengonversi tampilan khusus (SurfaceView, Surface atau Window) ke bitmap, Anda sebaiknya mempertimbangkan menggunakan kelas PixelCopy . Ini membutuhkan API 24 dan lebih tinggi. Saya tidak tahu bagaimana melakukannya sebelumnya.

pengembang android
sumber
Gagasan apa pun, tanpa TextView ditambahkan dalam bitmap. Hanya ImageViews yang ditambahkan.
Khemraj
@ Khraj Saya tidak mengerti pertanyaannya.
pengembang android
Itu salah saya TextView saya tidak ada di bitmap. Karena saya menerapkan tema warna terang, terima kasih atas balasannya.
Khemraj
1
@ Kraj Maaf, tapi saya masih tidak mengerti. Baiklah sekarang?
pengembang android
Ya bro, saya tidak tahu mengapa Anda tidak mendapatkan saya :). Saya punya satu TextView dalam tata letak yang ingin saya konversi dalam Bitmap. Layout memiliki satu ImageView dan satu TextView. ImageView dikonversi menjadi Bitmap. Tetapi TextView tidak muncul di Bitmap. Itu masalah. Setelah itu saya menyadari saya memiliki tema yang diterapkan yang membuat warna teks TextView putih. Aku telah memperbaikinya. Dan semuanya baik-baik saja sekarang. Terima kasih.
Khemraj
-3
view.setDrawingCacheEnabled(true);
Bitmap bitmap = Bitmap.createBitmap(view.getDrawingCache());
view.setDrawingCacheEnabled(false);
Ashutosh Gupta
sumber
Tolong jelaskan apa yang dilakukannya.
Paul Floyd