views:

5005

answers:

2

Hi folks,

I've used following function in some of my projects, but recently I've created a small example which suggest that it's not reliable (at least in some situations):

[NSString sizeWithFont:font constrainedToSize:size]
[NSString sizeWithFont:font constrainedToSize:size lineBreakMode:lineBreak]

I created a custom UITableViewCell class to achieve the results as seen in iPhone's Photo Album application e.g. Picture, with Album Name, and count of Pictures in the album. I used the above function to adjust my detail text (for count). Here's the code:

Interface File:

#import <UIKit/UIKit.h>

@interface CustomValue2Cell : UITableViewCell {
    UIImageView *cellImage;
    UILabel *cellTextLabel;
    UILabel *cellDetailTextLabel;
}

@property (nonatomic, retain) UIImageView *cellImage;
@property (nonatomic, retain) UILabel *cellTextLabel;
@property (nonatomic, retain) UILabel *cellDetailTextLabel;

- (void)setCellImage:(UIImage *)image withText:(NSString *)text andDetail:(NSString *)detail;
- (CGSize)getSizeOfText:(NSString *)text withFont:(UIFont *)font;

@end

Implementation File:

#import "CustomValue2Cell.h"

@implementation CustomValue2Cell

@synthesize cellImage;
@synthesize cellTextLabel;
@synthesize cellDetailTextLabel;

// Coordinate positions of Image, Text Label, and Detail Text Label
# define kImageXPosition    3
# define kImageYPosition    3
# define kImageWidth     37.0
# define kImageHeight    37.0

# define kTextXPosition  55
# define kTextYPosition  10
# define kTextWidth   200
# define kTextHeight     22

# define kDetailXPosition   55
# define kDetailYPosition   10
# define kDetailWidth    40
# define kDetailHeight   22

// Displacement value for Text Label with Detail Text Label
// Displacement value of 10-15 works with non-bold font
# define kCellSubviewDisplacement   20 

// Label Font Size for Text Label and Detail Text Label
# define kTextLabelFontSize  18
# define kDetailLabelFontSize   16

- (id)initWithFrame:(CGRect)frame reuseIdentifier:(NSString *)reuseIdentifier {
    if (self = [super initWithFrame:frame reuseIdentifier:reuseIdentifier]) {

     // Color and font for the main label
     UIColor *textLabelColor = [UIColor blackColor];
     UIFont *textLabelFont = [UIFont systemFontOfSize:kTextLabelFontSize];

     // Color and font for the detail label
     UIColor *detailTextColor = [UIColor darkGrayColor];
     UIFont *detailTextFont = [UIFont systemFontOfSize:kDetailLabelFontSize];

     // Highligted row color
     UIColor *highlightedTextColor = [UIColor whiteColor];

     // Define boundary of the cell contents
     CGRect rect;

     // Set properties of Image Thumbnail
     rect = CGRectMake(kImageXPosition, kImageYPosition, kImageWidth, kImageHeight);
     cellImage = [[UIImageView alloc] initWithFrame:rect];

     // Set properties of Name
     rect = CGRectMake(kTextXPosition, kTextYPosition, kTextWidth, kTextHeight);
     cellTextLabel = [[UILabel alloc] initWithFrame:rect];
     [cellTextLabel setFont:textLabelFont];
     [cellTextLabel setTextColor:textLabelColor];
     [cellTextLabel setHighlightedTextColor:highlightedTextColor];

     // Set properties of Value
     rect = CGRectMake(kDetailXPosition, kDetailYPosition, kDetailWidth, kDetailHeight);
     cellDetailTextLabel = [[UILabel alloc] initWithFrame:rect];
     [cellDetailTextLabel setFont:detailTextFont];
     [cellDetailTextLabel setTextColor:detailTextColor];
     [cellDetailTextLabel setHighlightedTextColor:highlightedTextColor];

     // Put Image, Name, and Value in Content View
     [[self contentView] addSubview:cellImage];
     [[self contentView] addSubview:cellTextLabel];
     [[self contentView] addSubview:cellDetailTextLabel];

     //Set cell selection style (Blue)
     self.selectionStyle = UITableViewCellSelectionStyleBlue;
    }
    return self;
}

- (void)setCellImage:(UIImage *)image withText:(NSString *)text andDetail:(NSString *)detail {
    cellImage.image = image;
    cellTextLabel.text = text;
    cellDetailTextLabel.text = detail;

    // Get an estimated size of text in the label, 
    // which will be used to estimate the position of detail label
    UIFont *textLabelFont = [UIFont systemFontOfSize:kTextLabelFontSize];
    CGSize size = [self getSizeOfText:text withFont:textLabelFont];

    // Re-set the frame of detail view
    CGRect frame = CGRectMake(kDetailXPosition, kDetailYPosition, kDetailWidth, kDetailHeight);
    frame.origin.x = frame.origin.x + size.width + kCellSubviewDisplacement;
    [cellDetailTextLabel setFrame:frame];
}

- (CGSize)getSizeOfText:(NSString *)text withFont:(UIFont *)font {
    return [text sizeWithFont:font constrainedToSize:CGSizeMake(kTextWidth, kTextHeight)];
}

- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
    [super setSelected:selected animated:animated];
    // Configure the view for the selected state
}

- (void)dealloc {
    [cellImage release];
    [cellTextLabel release];
    [cellDetailTextLabel release];
    [super dealloc];
}

@end

To test my custom class i prepared a list of fonts and displayed them in my table View. Code to get list of available fonts:

fontFamily = [[NSMutableArray alloc] initWithArray:[UIFont familyNames]];
fonts = [[NSMutableArray alloc] init];

for(NSUInteger i=0; i<[fontFamily count]; i++) {
 NSString *familyName = [fontFamily objectAtIndex:i];
 NSArray *array = [UIFont fontNamesForFamilyName:familyName];
 [fonts addObjectsFromArray:array];
}

Here's the code to return the cells:

// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *CellIdentifier = @"Cell";
    CGRect rect = CGRectMake(0.0, 0.0, 320.0, 50.0);

    CustomValue2Cell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
     cell = [[[CustomValue2Cell alloc] initWithFrame:rect reuseIdentifier:CellIdentifier] autorelease];
    }

    NSString *font = [fonts objectAtIndex:indexPath.row];
    NSString *detail = [NSString stringWithFormat:@"%d", [[fonts objectAtIndex:indexPath.row] length]];

    [cell setCellImage:[UIImage imageNamed:@"Pointy.gif"] withText:font andDetail:detail];
    [cell setAccessoryType:UITableViewCellAccessoryDisclosureIndicator]
    return cell;
}

Result: Text Label and Detail Text Label are overlapping for some values. e.g. "CouierNewPS-BoldMT" and "25" overlap each other, and in some other cases, they are not overlapping but they are very close.

Question: Is their a better alternative to -sizeWithFont function? Or, am i doing something very stupid to mess things up?

Sorry for a long post. Any help is appreciated. Thanking in anticipation.

A: 

Well, you never really say exactly what the problem IS. Does it return a size too large, too small, all on one line, or something else entirely?

When I do string sizing, I use

- (CGSize)sizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size lineBreakMode:(UILineBreakMode)lineBreakMode

and specify UILineBreakModeWordWrap for the line break mode. I'm not sure if this ends up returning essentially the same value or not, but I've found it to work for me.

Reference : NSString UIKit Additions Reference Class Reference

Ed Marty
added "result" section. basically i believe that these methods are not relaiable in calculating the bounds. surely in cases when the text is truncated and "..." is appended to the string for display, and maybe others.
Mustafa
A: 

CGSize size, constrainedSize;

constrianedSize.width = MAXFLOAT; constrainedSize.height = MAXFLOAT;

size = [text sizewithFont:systemFontofSize:14 constrainedToSize:constrinedSize lineBreakMode];

returned constrainedSize should have correct width/height of text.

iamiPhone