Imagine you have a normal table view where each row is an item on a conveyor belt. You will put the items in each cell of the table view but when you scroll you also want the background image (the conveyor belt) to scroll as well. How can you do this?
views:
229answers:
4You should be able to accomplish this by setting the background color of the table view:
tableView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"background.png"]];
I haven't tried this, so I'm not sure what the best approach would be, but one option would be to add your background image as a UIImageView to each of your cells so that every cell has a full-sized copy of your background image. Set clipsToBounds to NO on your cell, and give the bounds of the UIImageView a negative y value equal to the offset from your cell to the top of the table.
You may also want to consider using UIScrollView instead of UITableView.
UITableView is itself a UIScrollView, so you could try just adding your background image as a subview of your UITableView, but I'd be surprised if that worked. I'm guessing the UITableView implementation won't play nice with foreign subviews.
** EDIT **
While I still suspect that UIScrollView may be a more appropriate base class to use here, I decided to try the UIImageView trick I described above. It's fairly simple and doesn't consume excessive memory as long as all your UIImageViews share a single UIImage. Here's my sample code:
// LadderCell.h
#import <UIKit/UIKit.h>
@interface LadderCell : UITableViewCell {
UIImageView *backgroundImageView;
UILabel *titleLabel;
}
@property (nonatomic, retain) UIImageView *backgroundImageView;
@property (nonatomic, retain) UILabel *titleLabel;
- (void)setIndexPath:(NSIndexPath *)indexPath;
- (id)initWithImage:(UIImage *)theImage;
+ (NSString *)reuseIdentifier;
+ (CGFloat)height;
@end
// LadderCell.m
#import "LadderCell.h"
@implementation LadderCell
@synthesize backgroundImageView, titleLabel;
- (void)dealloc {
self.backgroundImageView = nil;
self.titleLabel = nil;
[super dealloc];
}
- (id)initWithImage:(UIImage *)theImage {
if (self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:[LadderCell reuseIdentifier]]) {
self.frame = CGRectMake(0.0, 0.0, 320.0, [LadderCell height]);
self.clipsToBounds = YES;
self.backgroundImageView = [[[UIImageView alloc] initWithImage:theImage] autorelease];
backgroundImageView.autoresizingMask = UIViewAutoresizingFlexibleRightMargin;
self.titleLabel = [[[UILabel alloc] initWithFrame:self.bounds] autorelease];
titleLabel.textAlignment = UITextAlignmentCenter;
titleLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
titleLabel.backgroundColor = [UIColor colorWithWhite:1 alpha:0];
[self addSubview:backgroundImageView];
[self addSubview:titleLabel];
}
return self;
}
- (void)setIndexPath:(NSIndexPath *)indexPath {
backgroundImageView.frame = CGRectMake(0.0,
-(CGFloat)indexPath.row * [LadderCell height] + 100.0,
backgroundImageView.frame.size.width,
backgroundImageView.frame.size.height);
}
+ (NSString *)reuseIdentifier {
return @"LadderCell";
}
+ (CGFloat)height {
return 30;
}
@end
// TableBackgroundTestViewController.h
#import
@interface TableBackgroundTestViewController : UITableViewController {
UIImage *backgroundImage;
}
@property (nonatomic, retain) UIImage *backgroundImage;
@end
// TableBackgroundTestViewController.m
#import "TableBackgroundTestViewController.h"
#import "LadderCell.h"
@implementation TableBackgroundTestViewController
@synthesize backgroundImage;
- (void)dealloc {
self.backgroundImage = nil;
[super dealloc];
}
- (void)viewDidLoad {
[super viewDidLoad];
self.backgroundImage = [UIImage imageNamed:@"background.png"];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)table numberOfRowsInSection:(NSInteger)section {
return 1000;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return [LadderCell height];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
LadderCell *cell = (LadderCell *)[tableView dequeueReusableCellWithIdentifier:[LadderCell reuseIdentifier]];
if (!cell) {
cell = [[[LadderCell alloc] initWithImage:self.backgroundImage] autorelease];
}
[cell setIndexPath:indexPath];
cell.titleLabel.text = [NSString stringWithFormat:@"Row %d", indexPath.row];
return cell;
}
@end
Have the UITableView
background transparent, and add a UIScrollView
behind it with the UIImageView
inside it. Add a listener for when the UITableView
scrolls (since it is a subclass of UIScrollView
it has all the same delegate methods). Then, when it scrolls, set the scroll position of the UIScrollView
behind it to the same programmatically.
You could technically do it without a second UIScrollView
behind the UITableView
, just with a plain UIIImageView
, if you want to reverse the offset values.
My suggestion is similar to Ed Marty (what he suggests "without a second UIScrollView"):
Place the UITableView inside a simple UIView. Make the cell backgrounds transparent so background from below the tableview would show
Below the UITableView, place an UIImageView with your desired background. Both the UITableView and UIImageView now sit inside the same enclosing UIView.
Listen to scroll events of UITableView. When detecting a scroll, simply change the background UIImageView position (frame.origin.y) appropriately, so that it would "stick with" the tableview.
You can have the background as one gigantic image, or have a series of them so you do tiling. You can have an array of the images and add to the array from top/bottom when needed, and also remove the images that have "scrolled away" from screen to conserve memory. You will need to calculate the positions for all these background images yourself, but there's nothing complicated in that.