UITableViewCell: how to give the built-in imageView a margin on retina display
I'd like to apply a margin to the UIImageView on the left of a plain old UITableViewCell (grouped style).
The only way I've found to do this (via here) is to resize the UIImage itself before attaching it to the UIImageView. If the image is smaller then the cell, it will be centred; leaving the desired margin as a side-effect.
Well, that works, but now my 开发者_运维知识库image is blurry because the 100 unit row height is not 100 pixels on an iPhone4, its 200. So I end up with a UIImage scaled to 90x90 pixels that produces a 90x90 unit (180x180 pixel) UIImageView image. Enter ugly blurriness.
So my question is: how do I achieve a margin around the imageView without over-downsampling my image? (ideally without downsampling at all - I need to keep the original for later anyway).
I feel like I'm missing something obvious; I really don't want to implement a custom cell class just for this.
Thanks guys, I've come up with a 'solution' that doesn't require subclassing.
What I do is still downsample the image, but to the 2x size (180x180 from the example in the question). Then, when I come to create the final UIImage from the processed CGImage I use:
UIImage: +(UIImage *)imageWithCGImage:(CGImageRef)imageRef scale:(CGFloat)scale orientation:(UIImageOrientation)orientation
and set scale: to 2. Now everything works. But I'm still creating duplicate images just to keep UIKit happy.
Implement this method in your UITableViewCell subclass
-(void) layoutSubviews
{
[super layoutSubviews];
self.imageView.frame = CGRectInset(self.imageView.frame, 5, 5);
}
Note: I haven't tested any of this, so it's possible that UITableViewCell
will override some of these settings to lay its subviews out according to its own internal logic.
Have you tried just adjusting the image view's frame? Try this:
UITableViewCell * tableViewCell = [[[UITableViewCell alloc] init] autorelease];
tableViewCell.imageView.image = [UIImage imageNamed:@"table-view-image"];
CGRect imageViewFrame = tableViewCell.imageView.frame;
imageViewFrame.origin.x += 10.0f;
tableViewCell.imageView.frame = imageViewFrame;
That will just pad the image view 10 points more than its normal x
coordinate. If you want to pad both sides, you can also set the contentMode
property on the image view to UIViewContentModeCenter
and adjust its width:
UITableViewCell * tableViewCell = [[[UITableViewCell alloc] init] autorelease];
tableViewCell.imageView.image = [UIImage imageNamed:@"table-view-image"];
tableViewCell.imageView.contentMode = UIViewContentModeCenter;
CGRect imageViewFrame = tableViewCell.imageView.frame;
imageViewFrame.size.width += 20.0f;
tableViewCell.imageView.frame = imageViewFrame;
That will make the image view 20 points wider, but because the content mode is set to center, the image will be drawn without stretching. If the dimensions of your image are right, this will effectively pad the image by 10 points on the left and right. However, you need to be aware that if you do this, the UIImage
you provide must already be the exact dimensions to fit in the image view. contentMode
's default setting is UIViewContentModeScaleToFill
, so it will automatically scale images to fill the image view's frame. Setting it to UIViewContentModeCenter
will no longer do this, but it will center the actual image.
In my case I used my own subclass inherited from UITableViewCell
.
It's very clean and easier to use.
Also, I could use different sizes of image to be well resized for this cell.
The point is to use additional property that will replace regular imageView
1: In the subclass, I added a property mainImageView
which can be used instead of imageView
.
@property (nonatomic, retain) UIImageView *mainImageView;
2: Then in - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
.
I allocated and initialized mainImageView
.
You can set any frame(rect) for mainImageView
.
Add it as a subview to the contentView
.
I used insetImageView
to align it to the vertical middle of `contentView'.
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code.
mainImageView = [[UIImageView alloc] initWithFrame:frameCellMainImageView];
[self.contentView addSubview:mainImageView];
insetImageView = (sizeRowHeightTwoLinedDetail - frameCellMainImageView.size.height) / 2.0;
}
return self;
}
3: Override - (void)layoutSubviews
to make sure other properties like textLabel
, detailTextLabel
set their frames to be well-situated with added property mainImageView
- (void)layoutSubviews {
[super layoutSubviews];
CGRect frameImageView = frameCellMainImageView;
frameImageView.origin.x = insetImageView;
frameImageView.origin.y = insetImageView;
[self.mainImageView setFrame:frameImageView];
// Use changed frame
frameImageView = self.mainImageView.frame;
CGFloat newLeftInset = frameImageView.size.width + insetImageView;
CGRect frameTextLabel = self.textLabel.frame;
CGRect frameDetailLabel = self.detailTextLabel.frame;
frameTextLabel.origin.x += newLeftInset;
frameDetailLabel.origin.x += newLeftInset;
CGFloat newTextWidth = 320.0;
newTextWidth -= newLeftInset;
newTextWidth -= insetImageView;
newTextWidth -= insetImageView;
frameTextLabel.size.width = newTextWidth;
frameDetailLabel.size.width = newTextWidth;
[self.textLabel setFrame:frameTextLabel];
[self.detailTextLabel setFrame:frameDetailLabel];
}
4: When using this cell in UITableDataSourceDelegate
methods, use cell.mainImageView
to receive messages, instead of regular cell.imageView
精彩评论