iOS 7.1 UitableviewCell content overlaps with ones below - ios

So I have code, which is sucessfully working on iOS 7.0 but not in 7.1. I have a simple tableview, with code:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 10;
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 70.0;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
for (UIView *view in cell.contentView.subviews) {
[view removeFromSuperview];
}
UILabel *label = [[UILabel alloc] init];
label.text = [NSString string];
for (NSInteger i = 0; i < 20; i++) {
label.text = [label.text stringByAppendingString:#"label String "];
}
label.translatesAutoresizingMaskIntoConstraints = NO;
label.numberOfLines = 0;
label.lineBreakMode = NSLineBreakByWorldWrapping;
//label.lineBreakMode = NSLineBreakByTruncatingTail; //I have tried this too
[cell.contentView addSubview:label];
NSDictionary *dict = NSDictionaryOfVariableBindings(label);
[cell.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-8-[label]-8-|" options:0 metrics:nil views:dict]];
[cell.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-8-[label]" options:0 metrics:nil views:dict]];
if (indexPath.row == 0) {
label.textColor = [UIColor colorWithRed:1.0 green:0 blue:0 alpha:1.0];
}
else if (indexPath.row == 1) {
label.textColor = [UIColor colorWithRed:0 green:1.0 blue:0 alpha:1.0];
}
else if (indexPath.row == 2) {
label.textColor = [UIColor colorWithRed:0 green:0 blue:1.0 alpha:1.0];
}
else {
label.textColor = [UIColor colorWithWhite:0.3 alpha:1.0];
}
cell.backgroundColor = [UIColor colorWithWhite:1.0 alpha:1.0];
return cell;
}
I have 1section with 10rows. With each row reused I delete all subviews from contentView(I tried alloc-init UITableViewCell, but came with the same results).
On iOS 7.0, UILabel is displayed only in cell it belongs to. But in 7.1 UILabel continues displaying over another cells. What is interresting, that when I click on cell, it stop being overlaping by anothers, but only till I click on cell above.
My question is, how to make it work on 7.1devices like on 7.0ones.
I tried both simulator and device and I took a look at iOS 7.1 API Diffs, but found nothing related to this.
Maybe it is issue of Auto Layout, that i have variable height of UILabel, but I need to do so. I want to have all text in UILabel, but display only part of UILabel, that can be displayed in a cell, which is default behavior in 7.0, but 7.1 changes this and I don't why why and how to deal with it.
This is dropbox folder for images with detail explanation: Folder with images
Update: I tried things like tese, but nothing worked for me.
cell.frame = CGRectMake(0, 0, self.tableView.frame.size.width, 70);
cell.contentView.frame = CGRectMake(0, 0, self.tableView.frame.size.width, 70);
cell.opaque = NO;
cell.contentView.opaque = NO;
cell.clearsContextBeforeDrawing = NO;
cell.contentView.clearsContextBeforeDrawing = NO;
cell.clipsToBounds = NO;
cell.contentView.clipsToBounds = NO;

The issue has to do with the height of your cell. It isn't going to dynamically adjust that for you.
You'll probably notice that as you scroll and the view above goes out of view the overlapping text will disappear with it.
If you are wanting your text to clip at a certain height, then you need to set the number of lines, rather than setting it to 0 since that will let it continue forever.
The lineBreakMode won't take effect since it isn't stopped.
Optionally you could try to set clipping on the contentView to make sure all subviews stay inside.
Depending on the end result you want, you could do dynamic heights and change based on the content. There are a bunch of SO questions related to doing this.
Update - clipping the contentView
I'd have to try it out myself, but in lieu of that, here are a couple links related to clipping the contentView:
stop the clipping of contentView - you'd actually want to do the opposite.
adding subview - looks similar to what you are trying to do.
Looks like this works:
cell.clipsToBounds = YES;

Here is the Perfect solution of Overlapping content in Cells.
Just use below code in cellForRowAtIndexPath after allocating cell and before adding subviews.
for (id object in cell.contentView.subviews)
{
[object removeFromSuperview];
}
Actually the overlapping is occurring because whenever you scroll the tableview its allocating your added view again and again. So above code will solve your problem by removing the existing views from cell's contentView.
Now You can see the memory debug session after applying above code, your memory is stable this time.
Hope it'll help you.
Thanks !

This is problem with recreating cell contents. Try with following code segment.
for(UIView *view in cell.contentView.subviews){
if ([view isKindOfClass:[UIView class]]) {
[view removeFromSuperview];
}
}

#Gaurav your answer should be the accepted answer. Thanks!
for object in cell.contentView.subviews
{
object.removeFromSuperview();
}

had similar behavior in iOS 8, using storyboard / IB.
fix was to add a Bottom Space to: Superview constraint from the bottom-most view to bottom of the prototype cell's Content View. The other views and constraints were all anchored from the top.

Are you using storyboards?
If so, select the table view controller in storyboards and uncheck the "Under bottom bars"
You can also do this programmatically.
If your TVC inherits from a nav view controller or a tab view controller, you may need to uncheck this layout option on the parent view instead

Re-checking all 4 constraints helps. While working with table view or collection view it's necessary to apply all four constraints (leading, trailing, top, bottom.)

Related

How to add subviews to a tableview cell dynamically

I created a custom tableview cell in IB. I add a scroll view as a subview of the cell's contentView, and create the IBOutlet in the tableview cell subclass, and make the connection. My problem is, I want to add subviews to the cell dynamically, but when I did this in code, nothing happens. The cell is rendered successfully, but the scrollView has nothing to show (no subviews on it).
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// deque the cell
// create some label depending on the MODEL object
// (this is done by code, not in IB. because the label is content-based)
// we don't know how many labels in advance
[cell.scrollView addSubview: label]; // not working !!
...
return cell;
}
But if I add the subviews in IB (which means the subviews are pre-defined), it works.
Is there any ways to add the subviews to a cell dynamically ? Or maybe I put the code in the wrong place ?
Thanks for all of the responses.
This is really embarrassing. The problem is I mis-config the label property, make the label text color white, but somehow the scrollView background is also white. So I can't see the labels, but actually they are already there.
All the responses are helpful, but #Shebin's answer gave me the hint to check the color, so I think I should mark his answer as the best.
Try this
UILabel *label1 = [[UILabel alloc]initWithFrame:CGRectMake(8, 8, 130, 30)];
label1.text = #"any text";
label1.textColor = [UIColor redColor];
label1.backgroundColor = [UIColor greenColor];
[cell addSubview:label1];// first try adding to cell
if you need to add as subview of cell.scrollView
NSLog(#"scrollView %#",cell.scrollView);//it should not be nil
check scrollView content size and frame
For dynamic string this will also help you
NSString *string = #"This is the text";
CGSize stringsize = [string sizeWithFont:[UIFont systemFontOfSize:[UIFont systemFontSize]]];
UILabel *label1 = [[UILabel alloc]initWithFrame:CGRectMake(8, 8, stringsize.width+30/*you have to adjust 30 as u required*/, 30)];
label1.text = string;
label1.textColor = [UIColor redColor];
label1.backgroundColor = [UIColor greenColor];
cell.scrollView.contentSize = CGSizeMake(label1.frame.size.width+30/*you have to adjust 30 as u required*/, label1.frame.size.height);
[cell.scrollView addSubview:label1];
You need to add proper constraints on your sub views. The scrollable size of a UIScrollView is computed based on the constraints of its subviews. Please ensure that constraints on the content view of your cell is properly added.
And if you are not setting constraints on your subview like label etc. then its intrinsicContentSize is used.

How to dynamically set background color for UITableView section headers?

I'm working on implementing UITableView section headers similar to the Photos app on iPhone. The top header view should have a grey background and the other header views should have a white background. Based on that I have a couple of questions I need help with:
How do I find out which section header is on top (e.g. adjacent to the nav bar)? Note, that the navigation bar is translucent (meaning it displays cells below itself), so I can't go by finding visible cells and then retrieving section based on that.
What should be the approach to change background color of the top section header to a different color and then back to the original color when it's no longer a top one?
Make the property NSUInteger sectionPath and initialize it with 0 in viewDidLoad.
Create a headerView and for specific section change backgroundColor of that view.
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, tableView.frame.size.width, 30)];
UILabel *headerLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, headerView.frame.size.width, headerView.frame.size.height)];
headerLabel.textAlignment = NSTextAlignmentCenter;
headerLabel.text = [titleArray objectAtIndex:section];
if(section == sectionPath) {
headerLabel.backgroundColor = [UIColor grayColor];
}
else {
headerLabel.backgroundColor = [UIColor whiteColor];
}
[headerView addSubview:headerLabel];
return headerView;
}
To dynamically find the top-most header in UITableView during scrolling
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
for (NSIndexPath* i in [yourTableViewName indexPathsForVisibleRows]) {
sectionPath = [i indexAtPosition:0];
}
}

Determine custom section header frame when tableView mode grouped

I provide a custom section header via the tableView's delegate method. It works fine in plane mode but I can't figure out the correct margin in grouped style.
Does anyone know how to make the section header aligned with the tableView cells?
You can create a custom label and adjust its frame accordingly.
For eg.
- (UIView *)tableView:(UITableView *)aTableView viewForHeaderInSection:(NSInteger)section
{
UIView *view=[[UIView alloc] initWithFrame:aTableView.tableHeaderView.frame];
UILabel *label=[[UILabel alloc] initWithFrame: CGRectMake(//set frame of the label as you want)];
[label setFont:[UIFont fontWithName: size:]];
[label setTextColor:[UIColor blackColor]];
[label setShadowOffset:CGSizeMake(0.0f, 1.0f)];
[label setShadowColor:[UIColor redColor];
label.backgroundColor=[UIColor clearColor];
if(section==0)
{
[label setText://set your section0 title];
}
else if(section ==1)
{
[label setText://set your section1 title];
}
[view addSubview:label];
[label release];
return [view autorelease];
}
Hope this helps :)
Not tested in every flavor but a good starting point.
In
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
pass the tableView.style parameter to your own method providing the header.
Create a view a frame like
CGRect(0,0,CGRectGetWidth(tableView.frame), CGRectGetHeight(tableView.frame)
but add a subview with a frame
CGRectInset(frame, 30,0)
if you have a grouped tableView style. Set a the autoresizingMask to flexible width and it works.
Slightly modified in a way that I had to give an additional parameter to the creation method for the SectionHeaderView as the margin is different for presentationStyle FullScreen and Formsheet.
CGFloat margin = 0;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
margin = style == UITableViewStyleGrouped ? modalStyle == UIModalPresentationFormSheet ? 28 : 38 : 0;
}
else {
margin = style == UITableViewStyleGrouped ? 5 : 0;
}
UIView *view = [[UIView alloc] initWithFrame:CGRectInset(frame, margin, 0)];
view.autoresizingMask = UIViewAutoresizingFlexibleWidth;
[self addSubview:view];

How to get the header view of a grouped table view?

I want to get all the views of a grouped table view to change the label color and to set the background color.
I found the answer, it's not possible to get the header view of a table view section. But you can implement the delegate tableView:viewForHeaderInSection: to recreate the header view and the label. The following code will give you the same header view and the exact label.
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
NSString *sectionTitle = [self tableView:tableView titleForHeaderInSection:section];
if (sectionTitle == nil) {
return nil;
}
// Create label with section title
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(20.0f, 5.5f, 300.0f, 30.0f)];
label.backgroundColor = [UIColor clearColor];
label.font = [UIFont boldSystemFontOfSize:16.5];
label.shadowColor = [UIColor whiteColor];
label.shadowOffset = CGSizeMake(0.0, 1.0);
label.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleWidth;
label.text = sectionTitle;
// Create header view and add label as a subview
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, self.view.frame.size.width, 44.0f)];
view.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleWidth;
[view addSubview:label];
return view;
}
That's great you figured out your solution.
A couple of suggestions:
Don't hardcode the CGRect for the width of your frame, but rather use self.view.size.width for the width (e.g. in case you're in landscape orientation or if Apple ever introduces an iPhone with a different screen size);
You probably want to use autoresizingMask for both the label and the view that holds the label, so that they'll resize as the screen orientation changes, or make sure you invoke [self.tableview reloadData] on orientation changes; and
This is obviously a single line label ... if that works for you great, otherwise you'd want to use sizeWithFont:constrainedToSize:lineBreakMode to determine the height, both for creating the label/view as well as responding to tableView:heightForHeaderInSection:.
You also need to add the textColor:
label.textColor = [UIColor colorWithRed:0.265 green:0.294 blue:0.367 alpha:1.000];

How to get a grouped UITableViewCell content area width without using a constant

I'm creating a table view controller for an iPad app. This view will potentially be displayed full-screen or within a modal view, so the size could be different each time it's displayed. I'd ideally like to make my code generic enough to work irrespective of the size it's displayed at. (As an academic exercise I'd also like the code to work on the iPhone too - but that's not really a requirement here.)
I'm using a grouped table view style. I want to embed a UITextField into the cell's view. I can get the text field into the cell OK (using cell.AddSubview), but when I use the grouped style, the text field is at the very left of the table - not where it should be in the white area.
I've looked around (e.g. at the UICatalog sample, and at the answers here) and all of the solutions to this problem seem to involve hard-coding a constant x offset for the border area. This x offset is around 35px on the iPad, but is around 20px on the iPhone.
It seems to me that there should be a better way of doing this, but I've yet to find it. I've tried looking at the rectangles cell.Bounds, cell.Frame, cell.ContentView.Bounds, and cell.ContentView.Frame - none of them have the 'actual' content area of a grouped cell.
Does anyone have another suggestion, or do I need to hard-code the value?
Thanks
add any UIViews to cell.contentView and set autoResizeMask property for this view
here is the sample of creating cell with UILabel and UITextField:
// custom cell implementation
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
if ( (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) )
{
self.label = [[[UILabel alloc] init] autorelease];
self.label.font = [UIFont fontWithName:#"Helvetica-Bold" size:17];
self.label.backgroundColor = [UIColor clearColor];
[self.contentView addSubview:self.label];
self.textField = [[[UITextField alloc] init] autorelease];
//this will make our textField resized properly
self.textField.autoresizingMask = UIViewAutoresizingFlexibleWidth;
self.textField.borderStyle = UITextBorderStyleNone;
self.textField.backgroundColor = [UIColor clearColor];
self.textField.textColor = [UIColor darkGrayColor]; //text color
self.textField.font = [UIFont systemFontOfSize:17.0]; //font size
self.textField.autocorrectionType = UITextAutocorrectionTypeNo; // no auto correction support
self.textField.keyboardType = UIKeyboardTypeDefault; // type of the keyboard
self.textField.returnKeyType = UIReturnKeyNext; // type of the return key
self.textField.clearButtonMode = UITextFieldViewModeWhileEditing; // has a clear 'x' button to the right
[self.contentView addSubview:self.textField];
self.selectionStyle = UITableViewCellSelectionStyleNone;
self.accessoryType = UITableViewCellAccessoryNone;
}
return self;
}
and in dataSource method
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
something like that
CustomCell* c = (CustomCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier1];
if (c == nil)
{
c = [[[CellWithPass alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier1] autorelease];
c.textField.delegate = self;
}
//in this method cell and cell subviews are not resized, so
//we are setting subviews frames here for cell with frame {{0,0},{320,44}}
c.label.text = #"label";
float w = [c.label.text sizeWithFont:c.label.font].width;
c.label.frame = CGRectMake(10, 0, w, 44);
c.textField.frame = CGRectMake(w + 10, 12, c.contentView.frame.size.width - w - 20, 20);
return c;
I also have been looking for a similar answer.
I am yet to find any kind of "good" answer, but this conversation does kind of shed some light as to why a call to contentView's frame doesn't return the actual frame minus the accessory's dedicated area and rounded edge padding:
UITableViewCell's contentView's width with a given accessory type
I've taken Barrett's advice and just adjusted the frame accordingly with hard coded values, but would be very interested if you find an answer that is better.

Resources