I would like to create a list of about 200 ImageViews (random heights) with the following layout in a 'collage' fashion:
Normally I would do this in a ListView for the peformance gained by using Adapters but since i want the images to be displayed in columns, and with different height (See picture Example ) depending on the pictures, I cannot use a single listview for this purpose.
I have tried implementing this layout with:
- Three ListViews with synchronized scrolling = Slow
- Single ListView with each row containing three images = Not allowing different heights
- GridView = Not allowing different heights
- GridLayout = Difficult to implement different heights programmatically. Because of no adapter, OutOfMemoryErrors are common
- FlowLayout = Because of no adapter, OutOfMemoryErrors are common
- ScrollView with three Vertical LinearLayouts = Best solution so far, but OutOfMemoryErrors are common
I have ended up using three LinearLayouts in a ScrollView, but this is far from optimal. I would rather use something with an Adapter.
EDIT I have been looking at the StaggeredGridView, as in a response below, but I find it quite buggy. Are there any implementations of this that are more stable?
Do you know why the 3 List View solution was slow?
How many different sizes are in each column? I think that for the recycling of views to be efficient, you would want to create a view type for each size of image, and then make sure that you use getItemViewType, to be sure that you're recycling the correct type of view. Otherwise, you will not get much benefit from the recycling. You would want to be able to just reset the source for the image view.
I think I have a working solution for you.
The main files mentioned here are also on PasteBin at http://pastebin.com/u/morganbelford
I basically implemented a simplified equivalent of the github project mentioned, https://github.com/maurycyw/StaggeredGridView, using a set of excellent LoopJ
SmartImageViews
.My solution is not nearly as generic and flexible as the
StaggeredGridView
, but seems to work well, and quickly. One big difference functionally is that we layout the images always just left to right, then left to right again. We don't try to put the next image in the shortest column. This makes the bottom of the view a little more uneven, but generates less shifting around during initial load from the web.There are three main classes, a custom
StagScrollView
, which contains a customStagLayout
(subclassedFrameLayout
), which manages a set ofImageInfo
data objects.Here is our layout, stag_layout.xml (the 1000dp initial height is irrelevant, since it will get recomputed in code based on the image sizes):
Here is our main Activity's
onCreate
, which uses the layout. TheStagActivity
just basically tells theStagLayout
what urls to use, what the margin should be between each image, and how many columns there are. For more modularity, we could have passed these params to the StagScrollView (which contains the StagLayout, but the the scroll view would have just had to pass them down the layout anyway):Before we get to the meat of the solution, here is our simple
StagScrollView
subclass. His only special behavior is to tell his main child (ourStagLayout
) which the currently visible area is, so that he can efficiently use the smallest possible number of realized subviews.Here then is the most important class
StagLayout
.First,
setUrls
sets up our data structures.Our main data structure is
ImageInfo
. It is a kind of lightweight placeholder that allows us to keep track of where each image is going to be displayed, when it needs to be. When we layout our child views, we will use the information in the ImageInfo to figure out where to put the actual view. A good way to think about ImageInfo is as a "virtual image view".See comments inline for details.
The rest of the magic happens in
StagLayout's
onMeasure
andonLayout
.Ok, now let's see how we actually arrange all the ImageInfos.
And, now let's see how we create, resuse and dispose of real
SmartImageViews
duringonLayout
.Remember that _viewportTop and _viewportBottom are set every time the user scrolls.
You can have a look at https://github.com/maurycyw/StaggeredGridView
I have not worked with it personally, but you could atleast steal some concepts.
Hope this helps!
I guess it can be implemented with three independent list view, only thing which you have to do it to inflate layout for imageview and add it to listview.
use following as layout parameters during inflation.
Layout Width : match_parent layout Height: wrap_content you can assign layout weight as .3 for all the three list view with layout_width as 0dp and height as fill_parent.
hope this helps.
Can't you use your current solution wrapped in a custom list ?
in getView method for each row inflate your existing solution (checking converview ofcourse) i.e. ScrollView with three Vertical LinearLayouts.