In UILabel how to multiline text with custom width - objective-c

My UILabel is in UITableViewCell and Here is my code
lblgoal = [[UILabel alloc] initWithFrame:CGRectMake(60,10, 250, 20)];
CGSize maximumLabelSize1 = CGSizeMake(230,9999);
lblgoal.numberOfLines = 0;
lblgoal.adjustsFontSizeToFitWidth = NO;
CGSize expectedLabelSize = [sg.subgoal_name sizeWithFont:lblgoal.font
constrainedToSize:maximumLabelSize
lineBreakMode:lblsubgoal1.lineBreakMode];
CGRect newFrame = lblgoal.frame;
newFrame.size.height = expectedLabelSize.height;
lblgoal.frame = newFrame;
But this only works if i put the width of UILabel to 200, if i put more than 200 width, then it all comes in one line with dotted at the end. And, UITableView cell width is more than 500.

Actually, make sure to set the linebreakmode to UILineBreakModeWordWrap in both your sizeWithFont function and your lblgoal label as below:
lblgoal.numberOfLines = 0;
lblgoal.lineBreakMode = UILineBreakModeWordWrap; //NSLineBreakByWordWrapping for iOS 6
EDIT: Try sizeToFit after you set the lineBreakMode.
[lblgoal sizeToFit];
Also make sure you do this inside the cellForRowAtIndexPath method.
You should also implement the following delegate method to make sure the height of your cell is also adjusted accordingly.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath

You have a fixed Width when you are checking for the MaximumLabelSize.
CGSize maximumLabelSize1 = CGSizeMake(230,9999);
Instead Use
CGSize maximumLabelSize1 = CGSizeMake(MAXFLOAT, MAXFLOAT);
But this will give the Oppurtunity to extend width to any extend. Which is not going to
work for u.. So set the Maximum Width to 500.
CGSize maximumLabelSize1 = CGSizeMake(500, MAXFLOAT);
And set the Frame for the Label :
CGRect newFrame = lblgoal.frame;
newFrame.size.height = expectedLabelSize.height;
newFrame.size.width = expectedLabelSize.width;

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (!self.lastIndexPath)
{
self.lastIndexPath = indexPath;
}
if ([self.lastIndexPath row] != [indexPath row])
{
UITableViewCell *newCell = [tableView cellForRowAtIndexPath: indexPath];
newCell.accessoryType = UITableViewCellAccessoryCheckmark;
UITableViewCell *oldCell = [tableView cellForRowAtIndexPath:self.lastIndexPath];
oldCell.accessoryType = UITableViewCellAccessoryNone;
self.lastIndexPath = indexPath;
}
else {
UITableViewCell *newCell = [tableView cellForRowAtIndexPath: indexPath];
newCell.accessoryType = UITableViewCellAccessoryCheckmark;
}

Related

Changing selectioncolor for UITableView grouped

Currently I'm trying to change the background selection color of a grouped UITableViewCell (non-subclassed) with the following code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
...
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
- (void)tableView:(UITableView *)tableView didHighlightRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
cell.contentView.backgroundColor = [UIColor yellowColor];
}
The following problem occurs:
Also Tried:
cell.selectedBackgroundView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, cell.frame.size.width - 17, cell.frame.size.height-3)];
cell.selectedBackgroundView.backgroundColor = coolBlue;
UIBezierPath *rounded;
rounded = [UIBezierPath bezierPathWithRoundedRect:cell.selectedBackgroundView.bounds byRoundingCorners:UIRectCornerAllCorners cornerRadii:CGSizeMake(8.0f, 8.0f)];
else
rounded = [UIBezierPath bezierPathWithRoundedRect:cell.selectedBackgroundView.bounds byRoundingCorners:UIRectCornerTopLeft|UIRectCornerTopRight cornerRadii:CGSizeMake(8.0f, 8.0f)];
CAShapeLayer *shape = [[CAShapeLayer alloc] init];
[shape setPath:rounded.CGPath];
cell.selectedBackgroundView.layer.mask = shape;
When I try using the above code part of the bottom of the cell gets cut off when I try to subtract 3 from the height. I'm subtracting 3 pixels in attempt to maintain the separator line.
Have you tried just using:
[cell setBackgroundColor:[UIColor yellowColor]];
It seems to work for me but my tableView might be set up differently than yours.

UIImageView inside a UITableViewCell

I'm trying to display a UIImageView inside a UITableViewCell.
Inside method - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath I have:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
CGSize cellSize = cell.frame.size;
CGFloat cellWidth = cellSize.width;
CGFloat cellHeight = cellSize.height;
CGRect imageFrame = CGRectMake(0, 0, 70, cellHeight);
UIImageView * image = [[UIImageView alloc] initWithFrame:imageFrame];
[image setImage:[UIImage imageWithContentsOfFile:#"cyan.jpg"]];
CGRect nameFrame = CGRectMake(80, 0, cellWidth-80, cellHeight/2);
UILabel * nameLabel = [[UILabel alloc] initWithFrame:nameFrame];
nameLabel.text = #"Name: John Doe";
CGRect jobFrame = CGRectMake(80, 20, cellWidth-80, cellHeight/2);
UILabel * jobLabel = [[UILabel alloc] initWithFrame:jobFrame];
jobLabel.text = #"Job: IT-Consultant";
[cell addSubview:image];
[cell addSubview:nameLabel];
[cell addSubview:jobLabel];
return cell;
}
The labels are displaying perfectly but I don't see the image.
Any help would be appreciated.
imageWithContentsOfFile: expects a path to be sent to it. Use imageNamed: instead, or get hold of the path first by using NSBundle's pathForResource... methods first to get the path.
Also, if the image is the same for every cell, you should add the image view inside the cell=nil block, or you will be adding the view over and over again.
Add it to the UITableViewCell contentView instead.
[cell.contentView addSubview:...];
Use the UITableViewCell's imageView property instead of what you're doing. To be more clear, use cell.imageView.image and set your UIImage to that.
Or if you wish the image's location to be more flexible, add the imageView to the cell's contentView. i.e: [cell.contentView addSubview:yourImageView];

iOS - heightForRowAtIndexPath does not fire during scrolling

I am writing a simple iOS app using Xcode4, which uses a table view to display a list of stories (fetched from a URL). I'm displaying the story titles as UILabels, and as a subview of the table cell.
I am over-riding heightForRowAtIndexPath to calculate the correct height for the cells according to the length of each story title. I'm adding the label to the cell in cellForRowAtIndexPath. When I run the app in the simulator, everything is rendered well. However: when I scroll down and scroll up, the labels get messed up. They get truncated and over-run. I debugged a little, and found that the heightForRowAtIndexPath method is not fired during scrolling, so the cell heights are not re-calculated, and therefore the label text overflows, and gets rendered ugly. Here is the relevant code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:#"Cell"];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:#"Cell"];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
[cell autorelease];
}
/* NOTE: code to load trimmedTitle dynamically is snipped */
NSString* trimmedTitle;
UIFont *cellFont = [UIFont fontWithName:#"Georgia" size:14.0];
CGSize constraintSize = CGSizeMake(280.0f, MAXFLOAT);
CGSize labelSize = [trimmedTitle sizeWithFont:cellFont constrainedToSize:constraintSize
lineBreakMode:UILineBreakModeWordWrap];
UILabel* tempLabel = [[UILabel alloc] initWithFrame:CGRectMake(60, 0, 230, labelSize.height)];
tempLabel.lineBreakMode = UILineBreakModeWordWrap;
tempLabel.text = trimmedTitle;
tempLabel.numberOfLines = 0;
[cell.contentView addSubview:tempLabel];
[tempLabel release];
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString* cellText; // code to load cellText dynamically is snipped off
UIFont *cellFont = [UIFont fontWithName:#"Georgia" size:14.0];
CGSize constraintSize = CGSizeMake(230.0f, MAXFLOAT);
CGSize labelSize = [cellText sizeWithFont:cellFont constrainedToSize:constraintSize lineBreakMode:UILineBreakModeWordWrap];
return labelSize.height + 20;
}
In situations like these I typically pre-calculate the heights of all of my rows, store them in an array, and then just returns those heights in heightForRowAtIndexPath. This way the tableview knows the height of each cell and cells be conform to that height even after reuse. I don't know of a way to force a calculation of the cell height beyond looking for when a cell will be viewable and reloading it, which seems too costly.
Update: some example code:
I have a method called - (void)calculateHeights which does the same calculation you had in heightForRowAtIndexPath, but stores the result in my mutable array heights_ ivar:
- (void)calculateHeights {
[heights_ removeAllObjects]
for (Widget *myWidget in modelWidgetArray) {
NSString* cellText; // code to load cellText dynamically is snipped off
UIFont *cellFont = [UIFont fontWithName:#"Georgia" size:14.0];
CGSize constraintSize = CGSizeMake(230.0f, MAXFLOAT);
CGSize labelSize = [cellText sizeWithFont:cellFont constrainedToSize:constraintSize lineBreakMode:UILineBreakModeWordWrap];
[heights_ addObject:[NSNumber numberWithFloat:labelSize.height + 20.0f]];
}
}
And then in heightForRowAtIndexPath, given a 1-section table view:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return [heights_ objectAtIndex:[indexPath row]];
}
If your table view has more than one section you'll need to do some math to convert to the one-dimensional heights_ array and back again. Also, any time you -reloadData you'll need to -calculateHeights as well.
The -tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath method is invoked before the scroll view is composed.
The purpose of calling this method before calling -tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath and not fired during the scrolling is that the table view (Which is inherited from UIScrollView) need to know the whole height of the contentView. Once the table view knows all the height, it cached the height before you call -reloadData
Your problem means you need to clear the content in the cell's -prepareForReuse and call -setNeedLayout to layout all the new contents.
you can use tag for your label to avoid messed up to each other
UILabel *label= (UILabel*)[cell viewWithTag:2];
label.lineBreakMode = UILineBreakModeWordWrap;
label.numberOfLines = 0;

Problems with UITableViewCell heights with a UILabel and random text lengths

I'm currently trying to get a UITableView to use custom cell heights based on text in an array. The problem I'm seeing is that the text seems to squish together at point rather than filling the full length of a custom cell. This results in the text overlapping over cells, sometimes disappearing under them.
Here's the code I have for determining the cell height, I'm not sure of the standard UILabel text height but this seemed to work well at the height I for the font.
if (indexPath.section == 0) {
NSString *text = [[self.recipeDict objectForKey:#"Ingredients"] objectAtIndex:[indexPath row]];
CGSize constraint = CGSizeMake(320 - (10 * 2), 20000.0f);
CGSize size = [text sizeWithFont:[UIFont systemFontOfSize:12] constrainedToSize:constraint lineBreakMode:UILineBreakModeWordWrap];
CGFloat height = size.height;
return height + 20;
}
Also just in case the creation of the cells is either a hinderance to my problem or just helps you know what's going on, here's that too.
UITableViewCell *cell;
UITableViewCell *ingredientCell;
UITableViewCell *methodCell;
if (indexPath.section == 0) {
UILabel *ingredientText;
static NSString *ingredientCellIdentifier = #"Ingredient Cell";
ingredientCell = [tableView dequeueReusableCellWithIdentifier: ingredientCellIdentifier];
if (ingredientCell == nil)
{
ingredientCell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier: ingredientCellIdentifier] autorelease];
ingredientText = [[UILabel alloc] initWithFrame:CGRectMake(15, 7, 290, 44)];
[ingredientText setLineBreakMode:UILineBreakModeWordWrap];
[ingredientText setNumberOfLines:0];
[ingredientCell.contentView addSubview:ingredientText];
ingredientText.tag = 1;
[ingredientText release];
ingredientCell.contentMode = UIViewContentModeRedraw;
}
ingredientText = (UILabel*)[ingredientCell viewWithTag:1];
ingredientText.text = [[self.recipeDict objectForKey:#"Ingredients"] objectAtIndex: indexPath.row];
[ingredientText sizeToFit];
return ingredientCell;
}
This is my second attempt at solving this issue but it seems to be beyond my current ability so I welcome wisdom gained through experience.
UPDATE -
After further investigation it seems that the UILabel ingredientText being resized is causing the issue.
It starts out as tall as it needs to be for the text shown, however when that label is redrawn with a larger height for another piece of text which requires more lines it's never shrunk down again. It seems that the sizeToFit method is prioritising using the available height rather than taking up the width and shrinking the height.
Right now I've set the width again after the sizeToFit which works around the issue but it leads to odd spacing depending on the height of the label.
A couple of things:
You have not set the font for the UILabel, which means you're sizing to an unknown height
You need to set your UILabel autoresizing mask, so that it sizes when the cell height changes
Here is working code (tested):
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.section == 0) {
NSString *text = [_items objectAtIndex:[indexPath row]];
CGSize constraint = CGSizeMake(320 - (10 * 2), 20000.0f);
CGSize size = [text sizeWithFont:[UIFont systemFontOfSize:12] constrainedToSize:constraint lineBreakMode:UILineBreakModeWordWrap];
CGFloat height = size.height;
return height + 20;
}
return tableView.rowHeight;
}
#pragma mark - UITableViewDatasource
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell;
UITableViewCell *ingredientCell = nil;
UITableViewCell *methodCell;
if (indexPath.section == 0) {
UILabel *ingredientText;
static NSString *ingredientCellIdentifier = #"Ingredient Cell";
ingredientCell = [tableView dequeueReusableCellWithIdentifier: ingredientCellIdentifier];
if (ingredientCell == nil)
{
ingredientCell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier: ingredientCellIdentifier] autorelease];
ingredientText = [[UILabel alloc] initWithFrame:ingredientCell.bounds];
ingredientText.font = [UIFont systemFontOfSize:12.0f];
ingredientText.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[ingredientText setLineBreakMode:UILineBreakModeWordWrap];
[ingredientText setNumberOfLines:0];
[ingredientCell.contentView addSubview:ingredientText];
ingredientText.tag = 1;
[ingredientText release];
ingredientCell.contentMode = UIViewContentModeRedraw;
}
ingredientText = (UILabel*)[ingredientCell viewWithTag:1];
ingredientText.text = [_items objectAtIndex: indexPath.row];
return ingredientCell;
}
}
Be sure you are always be returning a values for tableView:cellForRowAtIndexPath: and tableView:heightForRowAtIndexPath: methods
The solution to this issue was that the width specified in the constant in the cell height method didn't match the frame for the cell text specified later in the cellForRowAtIndexPath method.
Once these are the same the problem resolves itself.
The different constant size led to inconsistent and inaccurate UILabel heights being reported. This led to incorrect table row heights being set.

Adding extra UIlabel to each cell

I'm trying to add an extra UILabel into each cell(UITableView)
I'v succeeded with this code in
(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath method
Here's my code
//add another text
UILabel *test = [[UILabel alloc] initWithFrame:CGRectMake(250,80,50,20.0)];
test.text = [NSString stringWithFormat: #"test"];
test.backgroundColor = [UIColor clearColor];
test.font=[UIFont fontWithName:#"AppleGothic" size:20];
[cell addSubview:test];
However I figured that if I do this, I can't add different text to each cell, instead, it ends up with the same text in all cells. Can anyone tell me how to do that?
Oh and another problem was that if I do this, "test" is displayed in every cell except for the first one.
Have a look at the tutorial "UITableView – Adding subviews to a cell’s content view".
Try something like this
- (UITableViewCell *) getCellContentView:(NSString *)cellIdentifier {
CGRect CellFrame = CGRectMake(0, 0, 320, 65);
CGRect Label1Frame = CGRectMake(17,5,250,18);
UILabel *lblTemp;
UITableViewCell *cell = [[[UITableViewCell alloc] initWithFrame:CellFrame reuseIdentifier:cellIdentifier] autorelease];
lblTemp = [[UILabel alloc] initWithFrame:Label1Frame];
[lblTemp setFont:[UIFont fontWithName:#"Arial-BoldMT" size:15]];
lblTemp.tag = 1;
lblTemp.backgroundColor=[UIColor clearColor];
lblTemp.numberOfLines=0;
[cell.contentView addSubview:lblTemp];
return cell; // this I forgot
}
in cellForRowAtIndexPath
{
if(cell == nil)
cell = [self getCellContentView:CellIdentifier];
UILabel *lblTemp1 = (UILabel *)[cell viewWithTag:1];
lblTemp1.text =[nameArray objectAtIndex:value+indexPath.row];
return cell;
}
For having the same Label on all cells, you are probably instantiating just one cell and use the cellReUseIdentifier for all cells. So, I suggest that you create different labels as properties of the class, and assign each property-label to each cell.
// For example -
if (indexPath.row ==0 )
// assign [cell.contentView addSubview: self.label1];
if (indexPath.row ==1 )
// assign [cell.contentView addSubview: self.label2];
And for the second part of the question, please post your cellForRowAtIndexPath fully - there could be an error in that.
First check if any of the predefined styles work for you.
If you need more flexibility than what they offer, you can try something like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [self makeCell: CellIdentifier];
}
MyData *data = [self.data objectAtIndex:indexPath.row];
UILabel *lbl1 = (UILabel *)[cell viewWithTag:1];
UILabel *lbl2 = (UILabel *)[cell viewWithTag:2];
lbl1.text = data.text;
lbl2.text = data.auxText;
return cell;
}
- (UITableViewCell *)makeLensListCell: (NSString *)identifier
{
CGRect lbl1Frame = CGRectMake(10, 0, 140, 25);
CGRect lbl2Frame = CGRectMake(10, 150, 140, 25);
UILabel *lbl;
UITableViewCell *cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:identifier] autorelease];
// Label with tag 1.
lbl = [[UILabel alloc] initWithFrame:lbl1Frame];
lbl.tag = 1;
[cell.contentView addSubview:lbl];
[lbl release];
// Label with tag 2.
lbl = [[UILabel alloc] initWithFrame:lbl2Frame];
lbl.tag = 2;
lbl.textColor = [UIColor lightGrayColor];
[cell.contentView addSubview:lbl];
[lbl release];
// Add as many labels and other views as you like
return cell;
}
This approach also allows images and other views.