11

I'm trying to place various size images inside imageView of UITableViewCell. I get the image data asynch'ly, create the image, set the content mode of imageView and finally set bounds of imageView. But the code seems insensitive to any changes I made. I want the images to be centered in a 75x75 area. I wrote the below code for this purpose

UIImage* image = [UIImage imageWithData:data];
[holder.imageView setContentMode:UIViewContentModeCenter || UIViewContentModeRedraw];
[holder.imageView setImage:image];
[holder.imageView setBounds:CGRectMake(0,0,75,75)];
[holder.imageView setFrame:CGRectMake(0,0,75,75)];
[holder setNeedsLayout]; 

Where holder is the UITableViewCell. The result I get is always the same. All images have 75px height and different widths. Can someone help me solve this problem?

I have realized that setting contentMode and bounds properties does not have any effect in that code. I have added an NSLog after the last line and got the results as below:

NSLog(@"imageview:%@ bounds and contentMode:%@ %@",[holder imageView],[holder.imageView bounds],[holder.imageView contentMode]);

imageview:<UIImageView: 0x39ab8a0; frame = (0 0; 75 75); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x39a92b0>> bounds and contentMode:(null) (null)

Still no solution

Behlül
  • 3,412
  • 2
  • 29
  • 46

5 Answers5

45

Done, I finally found the solution, it cost me 3 hours though =)

The solution is to change properties like bound,frame,contentMode in -(void)layoutSubviews method of the custom UITableViewCell class. The "trick" is to write layout code in this method, otherwise the code does not have any effect.

Below code did the work for me. It makes rows of the table vertically aligned.

- (void)layoutSubviews {
    [super layoutSubviews];
    self.imageView.bounds = CGRectMake(0,0,75,75);
    self.imageView.frame = CGRectMake(0,0,75,75);
    self.imageView.contentMode = UIViewContentModeScaleAspectFit;

    CGRect tmpFrame = self.textLabel.frame;
    tmpFrame.origin.x = 77;
    self.textLabel.frame = tmpFrame;

    tmpFrame = self.detailTextLabel.frame;
    tmpFrame.origin.x = 77;
    self.detailTextLabel.frame = tmpFrame;

}
Behlül
  • 3,412
  • 2
  • 29
  • 46
11

So the problem with UITableViewCell's is that you have no control over the size of the built-in objects (namely imageView, contentView, accessoryView, backgroundView). When the table changes, your customizations get trampled over.

You can, as Behlul pointed out, force the sizes to be correct by using layoutSubviews, but the problem with that is that layoutSubviews is called every time the table scrolls. That is a lot of unnecessary re-layout calls.

An alternate, method is to add all of your content to the contentView. Similarly if you are customizing the background, you can create a transparent backgroundView and add your custom background view (eg myBackgroundView) as a subview of backgroundView.

This way you can place and size your items how you want them.

The down side is the stock messages are no longer received from the accessory or image views. You just have to create you own.

Hope that helps!

// This code is not tested
// MyCustomTableViewCell
- (id) init{
    self = [super initWithStyle: UITableViewCellStyleDefault reuseIdentifier:@"MyReuseIdentifier"];
    if(self){
        //image view
        my_image_view = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:@"default_image.png"]] retain];
        [my_image_view setFrame:CGRectMake(10,10,30,30)];
        [self.contentView addSubview:my_image_view];

        //labels
        my_text_label = [[[UILabel alloc] initWithFrame:CGRectMake(50,10,100,15)] retain];
        [self.contentView addSubview:my_text_label];
        //set font, etc

        //detail label
        my_detail_label = [[[UILabel alloc] initWithFrame:CGRectMake(50,25,100,15)] retain];
        [self.contentView addSubview:my_detail_label];
        //set font, etc

        //accessory view
        //Whatever you want to do here
        //attach "accessoryButtonTapped" selector to button action

        //background view
        UIView* background_view = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, 200, 50)] autorelease];
        [background_view setBackgroundColor:[UIColor greenColor]];
        background_view.layer.cornerRadius = 17;
        background_view.layer.borderWidth = 3;
        background_view.layer.borderColor = [UIColor whiteColor].CGColor;

        [self setBackgroundView:[[[UIView alloc] init] autorelease]];
        [self.backgroundView addSubview:background_view];
    }

    return self;
}

- (void) setLabelText: (NSString*) label_text{
    [my_text_label setText:label_text];
}

- (void) setDetailText: (NSString*) detail_text{
    [my_detail_label setText: detail_text];
}

- (void) accessoryButtonTapped{
    //call table view delegate's accessoryButtonTappedForRowWithIndexPath method
}
Brooks
  • 2,082
  • 2
  • 18
  • 26
  • This is actually the better method than the selected answer. You can also create a UITableViewCell via a xib, if you want to. Here's a tutorial on it: http://ijoshsmith.com/2011/07/16/creating-a-custom-uitableviewcell-in-ios-4/ – JRG-Developer Oct 04 '12 at 22:14
2

"UIViewContentModeCenter || UIViewContentModeRedraw" is equivalent to 1. It's also not a bitfield. You want UIViewContentModeCenter.

UITableViewCell.imageView is managed by the cell. If you want custom layout, try adding a view to contentView (I'm guessing what you mean by "centered in a 75x75 area"):

UIImageView * iv = [[[UIImageView alloc] initWithImage:image] autorelease];
iv.frame = (CGRect){{0,0},{75,75}};
iv.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin| UIViewAutoresizingFlexibleRightMargin;
iv.contentMode = UIViewContentModeScaleAspectFit;
[holder.contentView addSubview:iv];
tc.
  • 33,468
  • 5
  • 78
  • 96
  • Thank you! I solved the problem without using content view. I'll mark the question as answered after 2 days =) – Behlül Jun 28 '10 at 13:13
1

try changing the "contentMode" property of imageView to 'UIViewContentModeScaleAspectFit' or 'UIViewContentModeScaleAspectFill'

Sanniv
  • 1,892
  • 1
  • 17
  • 21
  • 1
    Thank you, I have tried your recommendation but it didn't work. I realised that whatever value I set to contentMode and bounds does not have any effect. I have edited my first post to reflect this. – Behlül Jun 28 '10 at 10:10
0

Create subclass of UITableViewCell:

@interface UITableViewCellSubClass : UITableViewCell

@end

@implementation UITableViewCellSubClass

- (void)layoutSubviews {
    [super layoutSubviews];
    self.imageView.frame = CGRectMake(0,4,32,32);
    self.textLabel.frame = CGRectMake(42,4,300,32);
}
@end
Harshal Wani
  • 2,249
  • 2
  • 26
  • 41