I've got a UITableViewCell *cell, which has a UIImageView *image and a UILabel *description subviews. Description label held the upper part of the cell, I need to locate the UIImageViewbetween the label and the bottom edge. Here's my code:
CGFloat bottomTextY = cell.labelDescription.frame.origin.y + cell.labelDescription.frame.size.height;
CGFloat newImageY = bottomTextY + (cell.frame.size.height - bottomTextY) / 2;
cell.image.center = CGPointMake(cell.image.center.x, newImageY);
But every time the position is different, it's not strictly between the label and the edge. Autolayout is off. Please, help me!)
To make your life easier, you should design your cell (prototype cell) within the storyboard. That cell will include your two fields (image and text). Then tag your fields and in
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
add something that looks like :
UIImageView * imageView = (UIImageView *)[cell viewWithTag:CELL_TAG_PHOTO];
imageView .image = [self.photoSource objectForKey:key] ;
Of course, the tag (number) of each element has to be unique since this is how the elements are identified (define them with #define CELL_TAG_PHOTO (tag_number))
Set the frame of the UIImageView, not the center property.
Example:
cell.imageView .frame = CGRectMake(0, CGRectGetMaxY(cell.descriptionLabel.frame), cell.frame.size.width, cell.frame.size.height - CGRectGetMaxY(cell.descriptionLabel.frame));
Related
I'm trying to create a custom cell with 4 UILabels and a UITextView. I've laid out the elements. The UITextView is not scrollable. The problem I face it placing the last UILabel under the UITextView. I've tried pinning both(either) to the superview and nothing seems to work. It is always under the UITextView no matter what as shown below:
What more should I do to move the UILabel below the UITextView?
This the only change I've made in my code:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
QXTInboxCell *inboxCell = (QXTInboxCell*)[self tableView:tableView cellForRowAtIndexPath:indexPath];
CGFloat width = self.tableView.frame.size.width - inboxCell.question.frame.origin.x - QUESTION_RIGHT_MARGIN;
CGSize size = [inboxCell.question sizeThatFits:CGSizeMake(width, 400)];
[inboxCell.question sizeThatFits:size];
return (inboxCell.question.frame.origin.y + size.height + 20);
}
Please help. I'm on XCode 5.0.2. Thanks.
Add the following constraints:
TextView to superview (top space)
TextView to label (bottom/top space)
label to superview (bottom space)
then (AFTER you set the text of the textView) call
[cell setNeedsLayout]
Of course this only works if you calculated the correct height for the cell in heightForRowAtIndexPath:.
I would like to dynamically adjust the width of a UIImage inside of a UITableViewCell, I'm using the storyboard to design the UITableViewCell, I just added a label and an image, the properties get updated correctly, I'm even loading the value of the width into the label to show that it's the correct value, for the image, I'm loading a background image that I want to repeat, but the image won't update the width initially, if I scroll up and down, the images are shown as expected, here's the code for the cellForRowAtIndexPath, I've also tried to put the code on the willDisplayCell method, same result
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"mycustomcell"];
int r = [[data objectAtIndex:indexPath.row] intValue];
UIImageView *img = (UIImageView *)[cell viewWithTag:2];
img.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"some_img" ofType:#"png"]]];
CGRect frame = img.frame;
frame.size.width = r*16;
img.frame = frame;
int n = img.frame.size.width;
UILabel *label = (UILabel *)[cell viewWithTag:1];
label.text = [NSString stringWithFormat:#"custom %d", n];
[cell setNeedsDisplay];
return cell;
}
I just want this to work initially as it works after scrolling, thoughts?
The dynamic resizing of contents of a tableview cell is a well known problem. While there are kludgy workarounds, I believe proper solution depends upon whether you're using autolayout or not:
If using auto layout, make sure that your cell's image view has a width constraint, and then you can change the constraint's constant:
for (NSLayoutConstraint *constraint in img.constraints)
{
if (constraint.firstAttribute == NSLayoutAttributeWidth)
constraint.constant = r*16;
}
Frankly, I'd rather use a custom UITableViewCell subclass and have an IBOutlet for the width constraint (e.g. imageWidthConstraint), and it saves you from having to enumerate through the constraints to find the right one, and you can simply:
cell.imageWidthConstraint.constant = r*16;
If not using auto layout, you should subclass UITableViewCell, use that for your cell prototype's base class, and then override layoutSubviews, and resize the image view there. See Changing bounds of imageView of UITableViewCell.
Regardless of which approach you adopt, using a UITableViewCell subclass eliminates the need to use viewForTag construct, which makes the view controller code a little more intuitive.
argh, removing Auto Layout fixed the problem
I am attempting to obtain this result to get a TitleTextLabel|DescTextLabel with the line to break the two. Just like this example the homepage is divided from the URL field.
Can someone please point me in the right direction? I have read online / & the documentation but cannot find the right answer I'm looking for. I appreciate your help!
Thanks
There are a couple of ways I can think of to add that dividing line. You could override drawRect, and draw the line there. Another way that could be done wholly in IB, would be to add a 1 pixel wide label (with a light gray background an no text) in between the left and right labels. The left label should have a fixed width and constraints to the left side of the cell and to the 1 pixel wide label. The right label should just have constraints to the 1 pixel wide label and the right side of the cell (no fixed width). The 1 pixel wide label should have 0 length constraints to the top and bottom of the cell and a fixed width.
You need to draw that line on the cell manually.
1) Create UIView subclass called CellDividerView Override the -drawRect: method in the UIView subclass CellDividerView.m. The drawing code fills the entire rect with a solid color, dark gray in this case.
- (void)drawRect:(CGRect)rect
{
CGContextRef currentContext = UIGraphicsGetCurrentContext();
CGContextSaveGState(currentContext);
CGContextSetFillColorWithColor(currentContext, [UIColor lightGrayColor].CGColor);
CGContextFillRect(currentContext, rect);
CGContextRestoreGState(currentContext);
}
In the table view delegate's -tableView:cellForRowAtIndexPath: you create and init a CellDividerView with the frame positioned where you want it on the cell. In the code below it is positioned 40pts to the right, 0pts from the top, and it is 1pt wide and spans the entire cell height vertically. Next, this view is added to the cell's contentView.
#define CELL_VIEW_TAG 1234
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
cell.detailTextLabel.text = [NSString stringWithFormat:#"Section %u", indexPath.section];
cell.textLabel.text = [NSString stringWithFormat:#"Row %u", indexPath.row];
// Configure the cell...
CellView *cellView = (CellView *)[cell.contentView viewWithTag:CELL_VIEW_TAG];
if (!cellView)
{
cellView = [[CellView alloc] initWithFrame:CGRectMake(40.0, 0.0, 1.0, cell.contentView.frame.size.height)];
[cell.contentView addSubview:cellView];
cellView.tag = CELL_VIEW_TAG;
}
return cell;
}
The result is something like this:
Using a custom cell style and adjusting the 40.0pt offset will allow you to accurately position the line where you want it.
It doesn't have the line dividing it by default, but try UITableViewCellStyleValue2
I am trying to create multi-line dynamic UILabels in UITableViewCells. I have a custom UITableViewCell that has a 'comment' label. The cell and the label are created in storyboard.
I can compute the heights of the UITableViewCells properly based on the multi-line data to be stored in the UILabel (using heightForRowAtIndexPath). However, my problem lies in the actual UILabel content. The UILabel content will display only 1 line of data on table load. However, once a cell containing multiline UILabel data moves offscreen and comes back on screen, the multi-line data appears properly in the UILabel with multiple lines. Is there any way to fix this so that the multi-line data appears properly on table load?
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
CustomCell *cCell = (CustomCell *)cell;
MyObject = [myArray objectAtIndex:indexPath.row];
cCell.commentLabel.frame = CGRectMake(65.0f, 28.0f, 243.0f, 200.0f);
cCell.commentLabel.text = MyObject.multi_line_text_data;
cCell.commentLabel.adjustsFontSizeToFitWidth = NO;
cCell.commentLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth;
cCell.commentLabel.font = [UIFont systemFontOfSize:13.0];
cCell.commentLabel.lineBreakMode = NSLineBreakByWordWrapping;
cCell.commentLabel.numberOfLines = 0;
[cCell.commentLabel sizeToFit];
}
Thanks!
Since you're doing this in the storyboard, you can set the necessary label properties there (lineBreakMode and number of lines). Just give the label a specific width constraint and constraints to the top, bottom, and left sides of the cell. Then, in code use sizeWithFont:constrainedToSize:lineBreakMode: in heightForRowAtIndexPath: to calculate the appropriate height for the cell based on the content of the label -- the label, because of its constraints, will expand along with the cell to the proper size. Something like this:
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
CGSize rowSize = [self.theData[indexPath.row] sizeWithFont:[UIFont systemFontOfSize:14] constrainedToSize:CGSizeMake(260, CGFLOAT_MAX) lineBreakMode:NSLineBreakByWordWrapping];
return rowSize.height + 30;
}
Here, 260 was the width I gave my label in IB, and the 30 is a fudge factor (determined empirically) to account for padding above and below the label.
I met the same problems. Unchecking Autolayout can fix it.
I've frustrated myself with this question for a couple of days. I'm trying to add a UILabel to a UITableViewCell. I want the UILabel to span the entire width of the cell, minus 5 or 10 on both the right and left sides for looks. My problem is in programmatically determining the size of the cell's frame in which to place the label. No matter which UITableViewStyle I use, the cell.contentVew.frame.size.width value is nowhere near the width of the cell frame itself.
For example, in the table I am constructing, I can achieve my desired result by subclassing UITableViewCell and creating a UILabel with a manually determined width (through just trial and error) by:
CGRectMake(10, 12, 397, self.contentView.frame.size.height);
But it's that 397 number that's vexing me. I want a way to programmatically determine what it should be for any width table or style. This should be a simple process by just determining the width of the entire frame of the cell and then subtracting 10 or 20 so the UILabel's edges don't actually touch the edge of the cell.
However, if I set the tableViewStyle to UITableViewStyleDefault and then try:
NSLog(#"Width: %f", self.contentView.frame.size.width);
I get 320. If I set the style to any of the other three styles, the returned number is 302. Even the 320 number isn't anywhere near the width of the cell frame (as with my manually determined number of 397).
What value do I need to access that will return the entire width of the cell's drawing frame? I'm sure, as with most vexing problems, the solution will make me want to slap myself on the forehead, but I'm to the point where I'm ready for it now.
EDIT for more info:
One clarification to anyone interested. This question of mine pertains primarily to a Grouped style table. For a plain style, the answer to my question above can be determined simply in the cellForRowAtIndexPath method by:
CGFloat cellWidth = [tableView rectForRowAtIndexPath:indexPath].size.width;
The problem I'm having is that the rectForRowAtIndexPath method returns the width of the frame in which the cell is drawn, which is fine for a plain style table since the cell width is the entire width of the frame. However, in a grouped table, the width of the cell is less than the width of the frame in which it is drawn, so this method will return a number that is quite a bit wider than the width of the cell. It's possible that the width of the cell in a grouped table style is a fixed number less than the width of the table frame, so this might be the way to solve the problem. I'll investigate that and answer my own question here if that's the case.
I have determined my own answer, and I hope it helps anyone faced with the same issue. The calculation of the margin of a grouped tableView I found on this StackOverflow answer.
This code will provide a label within a tableView cell that spans the cell with a margin between the two edges of the cell, and centered vertically within the cell.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
UILabel *label;
CGFloat groupedStyleMarginWidth, tableViewWidth;
UIFont *labelFont = [UIFont boldSystemFontOfSize:17.0]; // Set to whatever you like
NSString *labelText = #"Test String";
// Calculate the margin between the cell frame and the tableView
// frame in a grouped table view style.
tableViewWidth = tableView.frame.size.width;
if (tableView.style == UITableViewStyleGrouped) {
if (tableViewWidth > 20)
groupedStyleMarginWidth = (tableViewWidth < 400) ? 10 : MAX(31, MIN(45, tableViewWidth*0.06));
else
groupedStyleMarginWidth = tableViewWidth - 10;
}
else
groupedStyleMarginWidth = 0.0;
if (cell == nil) {
CGRect tableViewRect;
CGRect labelRect;
CGFloat x, y, w, h, labelMargin;
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
// Retrieve the rect of the table view.
tableViewRect = [tableView rectForRowAtIndexPath:indexPath];
// Set whatever margin around the label you prefer.
labelMargin = 10;
// Determine rect values for the label.
x = tableRect.origin.x + labelMargin;
// Calculate width of label
w = tableRect.size.width - (groupedStyleMargin * 2) - (labelMargin * 2);
// Calculate height of table based on font set earlier.
h = [labelText sizeWithFont:font].height;
// Calculate y position for the label text baseline to center
// vertically within the cell.
y = (tableRect.origin.y / 2) - (h / 4);
labelRect = CGRectMake(x, y, w, h);
label = [[UILabel alloc] initWithFrame:labelRect];
label.text = labelText;
label.tag = 0;
[cell.contentView addSubview:stepLabel];
[label release];
}
else {
label = (UILabel *)[cell viewWithTag:0];
}
Sounds like this would best be handled by auto layout constraints nowadays.