Updates at 2012-12-12: Please check out FlipView for an improved solution.
The demo in this post was born when we’re working on the Android port of OpenAphid-Engine. One of our engineers is a huge fan of Flipboard iOS. He decided to implement its page flip animation on Android.
If you don’t know about the effect, please install the APK file of our demo app to see how it looks:
The full source codes of the demo application is also available at Github:
The Flipboard animation is easy to achieve on iOS by using Core Animation. Things get a bit difficult on Android:
The view animation framework on Android is not flexible and efficient for versions prior to 3.0;
The Android layout system makes it even harder for advanced animation;
In order to apply flip effect for views with arbitrary structures and make the animation run smoothly, several tricks are used in our approach. OpenGL ES is used to render the animation for efficiency; a special view container is implemented to grab content of a view to OpenGL ES. Let’s go through them one by one.
The first page is displayed over the second page. We took a screenshot when the first page flipped by 75 degrees:
When the first page is flipping, its top half stays still while the bottom half flips around the horizontal center axis of the page; part of the second page is visible during the animation.
ViewGroup, FlipViewGroup, is used to manage the visibility of the two pages and serve content to OpenGL ES. Besides using a
LinkedList to manage normal sub-views, it also contains a
GLSurfaceView to play animation:
The GLSurfaceView is added as a sub-view automatically. The
onLayout method of
FlipViewGroup is overridden to monitor the changes of view dimension:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
As in line 14 to line 16, when a change of view dimension is detected and flipping is on, the OpenGL render updates the texture by taking a screenshot of the top view; then the top view is hidden while the
GLSurfaceView will display its content with flip animation.
GrabIt is a small utility to convert the content of a view to a
Bitmap. The result bitmap will be used to construct the texture for
Setup of GLSurfaceView and Renderer
GLSurfaceView instance is setup to use the following configurations:
- A RGBA_8888 surface with 16-bit depth buffer;
- It’s displayed on the top of the window;
- A custom renderer:
- The desired PixelFormat of the surface should support translucency;
- The rendering mode is set to make the renderer be called repeatedly;
The FlipRenderer maps the OpenGL pixels to 2D screen pixels one-by-one which is similar to what OpenAphid-Engine does for 2D games. And the origin of the coordinate system is bottom left.
The actual drawing process is managed in the instance of
FlipCards manages the content and structure of flip animation. It accepts a bitmap, which should be the screenshot of the first page, to build the texture for rendering. The texture is binded to two instances of
topCard renders the top half, which stays still;
bottomCard draws the flipping effect of the bottom half.
Card represents a quadrilateral in OpenGL space. Its
angle property controls the flip angle, which is accomplished by the following OpenGL codes:
1 2 3 4 5
Card instance also takes a texture to bind to it. Let’s take the
FlipCards for example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
The vertices of
topCard are set to make the card at the top half of the application screen. And its texture coordinates are set to render the top half of the first page.
In order to make the flip effect more realistic, a gray rectangle is rendered to cover the appealed area of the second page, which looks like a shadow of the flipping card casting on the second page.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
The snippets above should cover the core concepts of our approach. You can fork the project to support more effects as we can see in Flipboard iPhone, like page flip following touch moves, flip over of a page, and book flip effect etc.
BTW, we’re tackling some technical problems of OpenAphid-Engine Android version. Will keep you posted if a stable version is ready.