Sunday, April 17, 2011

Horizontally sliding grid of images in Android

For my Android app I wanted a swipeable and horizontally slideable 3x3 grid of images. If there were more than 9 images, a swipe should show the next 3x3 grid. Another requirement was that all should be in a ScrollView because there would be more on the screen above the 3x3 grid.
The first solutions that directly came to my mind were of course the GalleryView or a GridView or a horizontal ListView.
But the final solution was a ViewFlipper with TableLayouts as its children!
Below you can find my "journey" figuring out, experimenting and getting to the solution.

List View

Luckily for the horizontal ListView there was already a good example here. The result:

It really does work as a horizontal ListView, but it doesn't support the paging I was looking for; it is just a continuous list.
Sadly the code wasn't downloadable in one block (update: seems I just missed it at the top!), and it also contained typos (the layout tags were all lowercase), so it took me a while to get it all fixed and useable in an Eclipse project.
For people looking for the complete source code, you can find it here.
Note that the getView() has not been optimized yet, it creates a new view each time!
Also weird in the original code was the TextView within the ImageView, I changed the code to have them below each eachother.
An advantage of this implementation is that there is no "center locking" of the image anymore.

Gallery View

So the horizontal ListView didn't cut it, let's try a GalleryView (g1 in the code) with per item a standard GridView. That worked reasonably, except that the swiping didn't work anymore! Keypad scrolling still worked, kind of:

Luckily I found a fix for that, implementing a custom GridView that passes the fling on to the parent gallery (g2 in the code).

But then I still had to put it in a ScrollView... And then the trouble started, look at the vertical scrollbars that suddenly appear:


I ended up with quite some trial code which you can find here. Disclaimer: this is quite messy trial code so you are warned and I'm not supporting this code in any way; you are on your own here :)

Grid View

Making a GridView scroll horizontally in sets of 3x3 images just gave me headaches from the beginning. For example you can't set the number of rows, so it might sometimes show more rows than 3. And a GridView inside a ScrollView is also strongly warned against. Which btw also applies to ListView within a ScrollView. In general it even seems: a scrolling View inside another scrolling View is not a good idea and even strongly discouraged!
Furthermore, on a xlarge screen (WXGA) the gridview had almost its own will for laying out, making it look very different than on a HVGA screen.

The solution

After some more thinking I came across the solution: put Table Layouts of 3x3 images inside a ViewFlipper! Per table you can control how many images should be shown and it's quite easy to add swiping! Paging is then done per table. You can swipe left and right.
Page 1:

Page 2 after swiping to the left:

The source code of the final solution you can find here.
Note the top left icon in the grid changes when you swipe to the left the first time (so you can tell that the 2nd page is showing).
Note also the use of the FixedViewFlipper to handle rotation correctly.
A future improvement: keep track of the "page" you're on so with the example of 2 tables, don't allow the swipe/fling to "go round", i.e swiping to the left on the 2nd table shows the first table again...

PS: of course you could also create your custom component, but I want to avoid that as much as possible to minimize (custom) maintenance.


These links I also stumbled upon but didn't do anything with:

Hope this helps somebody some time :)


Anonymous said...

Thanks Man for this blog post,
This is very useful explanation & Useful Source Code.
Please Keep It Up :)

Hansen Rio said...

Thanks for this useful post! Keep them coming! ~ciao

Swapnil Kulkarni said...

Great Tutorial Sir very useful source code.

Tharaka Nirmana said...

This is just what I was looking for. Thank you!

Anonymous said...

Thank you, very convenient code

Abdur Rehman Arshad said...

Good job.. You definately have a big heart... Thanks

Keval Mangukiya said...

Thanks Man for this blog post,
This is very useful explanation & Useful Source Code.

Keep it....