These utility methods will render a list of drawables to a canvas, stretching the drawables to "cover" the canvas while maintaining their aspect ratio. The layers are blended by setting the PorterDuff blend mode on the Paint
object. The code can be easily updated to support different blend modes for different layers.
Visit giferator for a web demo (with more blend modes).
It may be possible to use a LayerDrawable
to accomplish this, but it isn't quite as configurable.
Below is that boilerplate view and surface rendering code, which usually lives in your fragment or activity's onCreate()
:
List<Drawable> drawables = new List<>();
SurfaceView surfaceView = new SurfaceView(context);
final Layer layer;
surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
public void surfaceCreated(SurfaceHolder holder) {
ImageUtil.render(surfaceView, layer, drawables, paint);
}
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
layer = new Layer(width, height);
ImageUtil.render(surfaceView, layer, drawables, paint);
}
public void surfaceDestroyed(SurfaceHolder holder) {
// clean up.
}
});
Notice that paint
is missing, and it can be initialized like this:
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SCREEN));
For those using Glide's GifDrawable, make sure to set a callback like this:
drawable.setCallback(callback);
drawable.start();
Also, create a new thread to use in your callback:
HandlerThread thread = new HandlerThread("Gifs");
thread.start();
handler = new Handler(thread.getLooper());
and use that handler
inside your callback
. This keeps the rendering off the main thread.