Sunday, 15 November 2009

Android Reflective Surface

Reflection effect is pretty easy once you understand UI basics under Android.

Before going to platform specific implementation though, let's consider how this effect can be achieved in a graphics editing program (e.g. Inkscape, Photoshop)

First we select an area to be reflected, then we copy it to the desired place and flip it vertically. That's it, we may optionally overlay it with some gradient to achieve this cool fading out effect.

Now, back to Android implementation. I want to place my UI elements within a RelativeLayout and have it reflected to some ImageView every time whenever an element within that RelativeLayout gets redrawn.

Every UI element inherits from View class and so does RelativeLayout. View.onDraw(Canvas) gets called when a view needs to render its content. We need to override this method so that it triggers reflection. Within that method we need to notify ImageView to redraw itself using postInvalidate method. To do that I have created ReflectableLayout class.

Now here is a trick, we override ImageView's onDraw method as well, to do so I created ReflectiveSurface class. Inside that method we call ReflectableLayout's draw(Canvas) method with RelfectiveSurface's canvas as a parameter. This causes ReflectableLayout to render its content onto ReflectiveSurface. We just need then to add some canvas translations to the process.

That's basically it. If you need some gradient to your reflection you may add it in the XML layout file by placing gradient image over ReflectiveSurface. Source code (GPLv3 license) to this example is attached here.