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.

Author: Arpit Mathur

Arpit Mathur is a Principal Engineer at Comcast Labs where he is currently working on a variety of topics including Machine Learning, Affective Computing, and Blockchain applications. Arpit has also worked extensively on Android and iOS applications, Virtual Reality apps as well as with web technologies like JavaScript, HTML and Ruby on Rails. He also spent a couple of years in the User Experience team as a Creative Technologist.

9 thoughts on “Capturing Bitmaps of Views in Android”

Leave a comment