views:

1514

answers:

4

I'm building an iPad app, and would like to use a "tiled" display with objects arranged in a scrollable grid, similar to the iPhone/iPad home screen and the iPad photos app.


What I'm trying to achieve:

(iTunes link)

Is there any pre-built way in the SDK to do this? If not, how should I go about creating my own?

Update: I think I understand how to do a basic arrangement of the "objects" in a grid, but I don't know how to make this work with thousands of objects and a scrollable view without using tons of memory and making everything really slow (then again, I still don't have a device to test on).



Update 2:

Half a month later, I finally found the ideal solution: AQGridView

+1  A: 

I'm not aware of any pre-built way to do this, but there are generally two approaches you would want to take:

1) If the grid will not (really) change, you can simply create it directly in interface builder.

2) If you want a more flexible approach, you can programmatically build the grid in a UIViewController by calculating the appropriate position of each element. For example:

for(int i=0 ; i<num_rows ; i++) {
    for(int j=0 ; j<num_cols ; j++) {
        UIView *myView = [[UIView alloc] initWithFrame:CGRectMake(j*50, i*50, 40, 40)] ;
        [self.view addSubview:myView] ;
        [myView release] ;
    }
}
drootang
Replace UIView with any custom sub-class of UIView
drootang
I had thought of #2 earlier, but my problem comes when dealing with thousands of items and scrolling, etc. Do I have to rebuild a UITableView-esque thing?
igul222
+1  A: 

I'd suggest to use the Three20 library and adapt the TTLauncher view controller.

dwery
A: 

Use or derive from UIScrollView for the view that contains all the tiles. Either implement the delegate - (void)scrollViewDidScroll:(UIScrollView *)scrollView; method or override the - (void)setContentOffset:(CGPoint)contentOffset method. Set the content size of the scroll view as if all the tiles were present.

When the scroll view scrolls, figure out which tiles will be shown on screen. Then either use a recycling scheme like UITableView does with cells, or just add newly created tiles as needed and delete ones that are farthest from the visible area when you have reached your memory quota. Your example shows 2x3 tiles fully visible so you would need to keep at least 4x5 tiles present.

If you have two columns of tiles and no horizontal scrolling (not clear from picture), you can just use a UITableView directly and implement a custom UITableViewCell that displays two tiles.

If you are deriving from UIScrollView, a best practive would be to mirror the interface used by UITableView with dataSource and delegate callbacks. You would have numberOfRows:, numberOfColumns: and tileForRow:column: instead of numberOfRows:, numberOfSections:, and cellForIndexPath: but the principal is the same. It looks like you can use fixed sized tiles which simplifies things a lot.

drawnonward
Thanks- this helped a lot. In my implementation, I put the layout code in `layoutSubviews` of my UIScrollView subclass, which seems to work fine. Is there any particular reason you suggest I implement `scrollViewDidScroll:`?
igul222
You had the choice of deriving from UIScrollView or being a delegate. If you had chosen to be a delegate of a vanilla UIScrollView, you could have done the layout work in scrollViewDidScroll.
drawnonward
Ah, OK. Got it! For reference: overriding layoutSubviews was giving me major troubles when doing animations, etc. Implementing scrollViewDidScroll as a delegate fixes everything.
igul222
A: 

You could use a UITableView and have rows without lines between them and use four different types of rows each containing two subviews. This will deal with all the caching of the views for you. You can then ignore didSelect... and simply implement touches for the views you add to the contentView of the cells.

Felix