开发者

UITableViewCell: how to give the built-in imageView a margin on retina display

开发者 https://www.devze.com 2023-02-09 06:30 出处:网络
I\'d like to apply a margin to the UIImageView on the left of a plain old UITableViewCell (grouped style).

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

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号