Capturing Bitmaps of Views in Android

One of the most common techniques for animations (regardless of UI technology, Flash, iOS or Android) is to animate a Bitmap of the view being manipulated rather than the actual view itself since animating the view requires moving all subviews and for animations that distort the view dimensions, may cause expensive reflow of the internal components, not to mention the weird glitches as the internal components resize or reflow.

The core animation engines in both iOS and Android do this work for you themselves. When an object is animated, its only its drawing layer that gets moved. Thats why in Android, if you dont call setFillAfter(true) for an animation, the position of the View as Android understands it and its display on the screen diverge and buttons etc become unclickable. In the new Android animation framework introduced in HoneyComb, the animation framework even includes a withLayer() option that is advisable to use that draws the bitmap to a hardware accelerated layer and moves that which would perform better than the software option.

But grabbing the Bitmap of a View has other uses as well (like modifying photographs, taking screenshots of interesting points in a game etc). Here are 2 ways of doing that.

Method 1:

A View can actually draw itself on any instance of a Canvas class (usually at the end of the measurement and layout process, it draws itself onto a Canvas instance that is internal to the View class). So you can pass it a fresh instance of a Canvas thats constructed off a Bitmap object that you created like so:

	Bitmap b = Bitmap.createBitmap(targetView.getWidth(),
				       targetView.getHeight(),
				       Bitmap.Config.ARGB_8888);
	Canvas c = new Canvas(b);
	targetView.draw(c);
	BitmapDrawable d = new BitmapDrawable(getResources(), b);
	canvasView.setBackgroundDrawable(d);

Method 2:

This way was mentioned in a couple of posts I read, but there is a gotcha. This involves getting a Views drawingCache which is a Views own reference to its bitmap. Note that drawingCaches aren’t always available and so you may need to actually have the View generate it. You can do this by either setting setDrawingCacheEnabled(true) on the View or manually calling View.buildDrawingCache() and then using the Bitmap generated in the same way as previously mentioned. The gotcha I found was that the generated bitmap can be disposed without your knowledge. Since its recommended that calling the buildDrawingCache should be matched with a destroyDrawingCache(), you have to copy that bitmap data into a bitmap you own.

    targetView.buildDrawingCache();
   	Bitmap b1 = targetView.getDrawingCache();
   	// copy this bitmap otherwise distroying the cache will destroy
   	// the bitmap for the referencing drawable and you'll not
   	// get the captured view
   	Bitmap b = b1.copy(Bitmap.Config.ARGB_8888, false);
   	BitmapDrawable d = new BitmapDrawable(b);
   	canvasView.setBackgroundDrawable(d);
   	targetView.destroyDrawingCache();

The code for this project is on Github as well. Since I am only getting into this aspect of Android, let me know if I there is a better way to do this.

6 thoughts on “Capturing Bitmaps of Views in Android”

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s