iOS UITableView unexpectedly adding margins - ios

I have a UITableView, and currently it has a single cell in it. I have written a custom TableViewCell class which inherits from UITableViewCell in order to do some custom drawing. I have set the width of the table to the desired size, and am trying to set the width of the cell to the same size, so it will fill up the entire width of the table. The problem seems to be that I'm getting some margins on the left and right sides of the cell, and I don't know why.
Here's an example of the problem.
I made the TableView background black to be more clear. The TableView is the correct size. The background image is added to the cell, not the table, and it should be taking up the full width of the table.
I have tried making the TableView wider (as wide as the screen) to try to accommodate the size of the background image, but that doesn't quite do it. I would rather just figure out where these margins are coming from, and how I can get rid of them.
The TableView itself is initialized in Interface Builder. The style is set to Grouped, scrolling is disabled, and the view mode is set to Scale To Fill.
Here's the cell class' initWithStyle method
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
// Initialization code
_primaryLabel = [[UILabel alloc] init];
_primaryLabel.textAlignment = UITextAlignmentLeft;
_primaryLabel.font = [UIFont systemFontOfSize:18];
_primaryLabel.backgroundColor = [UIColor clearColor];
_detailLabel = [[UILabel alloc] init];
_detailLabel.textAlignment = UITextAlignmentLeft;
_detailLabel.font = [UIFont systemFontOfSize:12];
_detailLabel.backgroundColor = [UIColor clearColor];
_icon = [[UIImageView alloc] init];
[self.contentView addSubview:_primaryLabel];
[self.contentView addSubview:_detailLabel];
[self.contentView addSubview:_icon];
self.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
UIImageView* whiteDisclosureView = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, 15, 13)];
[whiteDisclosureView setImage:[UIImage imageNamed:#"white_disclosure.png"]];
self.accessoryView = whiteDisclosureView;
UIImageView * background = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, 305, 61)];
[background setImage:[UIImage imageNamed:#"button_silver.png"]];
[self setBackgroundView:background];
self.backgroundColor = [UIColor clearColor];
self.frame = self.contentView.frame = CGRectMake(0, 0, 305, 61);
}
return self;
}

Is your tableView using "grouped" style? With grouped style, iOS normally adds left and right margin for the table cells.
It may be possible to remedy this by adjusting the frame of the tableView to slightly outside its superview. See here for example in previous question

You shouldn't explicitly set your cell's frame (size), but declare its style. (If you don't do that already) The cells are designed to automatically take up the whole space. (Horizontally)
cell = [[CustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
If not when allocating your cell, how do you set the cell's frame?
EDIT: Instead of using hardcoded frame sizes, use self.frame. Additionally, remove the last statement where you set the frame.

Another alternative solution I used.
#jonkroll's solution does work but it does not fulfil my need. I have a header section in the table view which I want to keep the margin left and right as is, but want to remove them on the normal cell.
The solution I did is to implement a layoutSubViews method in a custom table view cell. Within this method, set the contentView's width equal to table cell's width.
-(void)layoutSubviews {
self.contentView.frame.size.width = self.frame.size.width;
}
This may be very late, but I think some people will run into the same problem as well. Hope this solution works for you guys : )

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.

Adding a UIImageView as a subview of UILabel, image not appearing

So, when I do this with a regular old view:
UIView *topBlock = [[UIView alloc] initWithFrame:CGRectMake(0,-frameSize.height, frameSize.width, frameSize.height/2)];
[viewController.view addSubview:topBlock];
topBlock.autoresizesSubviews = NO;
topBlock.clipsToBounds = YES;
UIImage *topImage = [UIImage imageNamed:#"BloktLayout"];
UIImageView *topImageView = [[UIImageView alloc] initWithImage:topImage];
topImageView.frame = viewController.view.frame;
[topBlock addSubview:topImageView];
I get the nice old image where I want it, in the top view. But the middle view is a UILabel, and when I try the same thing:
UILabel *midBar = [[UILabel alloc] initWithFrame:CGRectMake(midBarOrigin.x, midBarOrigin.y, midBarWidth, midBarHeight)];
midBar.text = #"Blokt";
midBar.textColor = [UIColor blackColor];
midBar.textAlignment = NSTextAlignmentRight;
midBar.font = [UIFont fontWithName:#"HelveticaNeue-UltraLight" size:80.0f];
[viewController.view addSubview:midBar];
midBar.autoresizesSubviews = NO;
midBar.clipsToBounds = YES;
UIImage *midImage = [UIImage imageNamed:#"BloktLayout"];
UIImageView *midImageView = [[UIImageView alloc] initWithImage:midImage];
midImageView.frame = viewController.view.frame;
[midBar addSubview:midImageView];
I don't see any image at all in the UILabel. Any help?
Seems like the issue is related to your frames.
Tough to say without additional info. Can you post viewController.view.frame, frameSize, and midBarOrigin / midBarWidth / midBarHeight?
In the second codeblock, midBar.clipsToBounds == YES, but it looks like the midImageView.frame is likely very different / outside of midBar.frame in which case it wouldn't be visible.
Edit Some screenshots would help but aren't necessary
Edit 2 Note that subviews' origin points are always relative to the coordinate system of their superview, never relative to the coordinate system of any other view in the view heierarchy. This is likely the heart of the issue here. If you do want to convert CGPoints or CGRects from one coordinate system to another there are methods on UIView such as convertRect: and convertPoint: etc.
Interface Builder doesn't even let you add a control inside of a UILabel.
Instead, if you wish to group multiple controls, you can add them both as subviews of a UIView.
In other words, your image view and label can share the same superview, but the image view cannot be a subview of the label.
If they share the same superview, you can position the image view behind the label, and it should appear "through" the label as long as the label's background is clear.
Simple Way to do.....
You can add UIImageView, UILabel as subview of cell.textLabel
UIImageView *statusImage = [[UIImageView alloc] initWithFrame:CGRectMake(0, 4, 8, 8)];<br/>statusImage.backgroundColor = [UIColor redColor];<br/>
statusImage.layer.cornerRadius = 4;<br/>
statusImage.clipsToBounds = YES;<br/>
[cell.textLabel addSubview:statusImage];<br/>
UILabel *Lbl = [[UILabel alloc] initWithFrame:CGRectMake(15, 0, cell.textLabel.frame.size.width - 15, cell.textLabel.frame.size.height)];<br/>
Lbl.text = #"xyz";<br/>
[cell.textLabel addSubview:Lbl];<br/>
I just had this problem as well.
I found that ImageView was behind the label.
When I replaced label with UIView, it works properly.

How to keep the text of cell label at top when cell's height increases?

I am increasing cell's height in the method heightForRowAtIndexPath, as a result of it, the label is coming centered.
How do make sure that label is still at top with the text irrespective of the height of the row?
While allocating UITableViewCell, you need to do like this..
UITableViewCell * cell;
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:string];
At the time of initialization with style: UITableViewCellStyleSubtitle will come.
Hope this will work..
You can do it in two ways.
Create a custom label and set it's frame.
UILabel *lbl = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, WIDTH, HEIGHT)];
[cell.contentView addSubView:lbl];
Use a UITableViewCell subclass and override -layoutSubviews. In this method, you'll want to call [super layoutSubviews].
- (void)layoutSubviews {
[super layoutSubviews];
CGSize size = self.bounds.size;
CGRect frame = CGRectMake(0.0f, 0.0f, size.width, size.height);
self.textLabel.frame = frame;
self.textLabel.contentMode = UIViewContentModeScaleAspectFit;
}
Write Following Code:
UILabel *myLable = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, width, height)];
[cell.contentView addSubView: myLable];
If Also You want myLable fram is similare to myLable.text then write..
[myLable sizeToFit];
You cannot change the position of textlabel as it is auto-adjusted.
First option is you need to subclass UITableViewCell and customize textLabel frame.
Another is that you create your own custom label and make textlabel nil. So whenever cell's height will change, your label position will not change.
Set the autolayout Top property of UILabel.
try this:
set False to "Autoresize Subviews" property of your custom cell...

Vertical space between UITableViewCells after setting the backgroundView on a cell

I am implementing UITableViewCells that have a custom background and expands when tapped.
I am setting a custom view as my UITableViewCells backgroundView: (in RowForIndexPath)
if (cell == nil) {
CGRect f = CGRectMake(0.0f, 0.0f, 300.0f, 50.0f);
cell = [[UITableViewCell alloc] initWithFrame:f reuseIdentifier:cellIdentifier];
UIView *back = [[UIView alloc] initWithFrame:CGRectMake(10.0f, 10.0f, 300.0f, 50.0f)];
back.layer.cornerRadius = 8.0f;
[back setBackgroundColor:[UIColor blackColor]];
This works fine, by setting the backgroundView instead of the contentView, my backgroundView scales to accommodate the new size of the cell after it expands (changing the height in heightForRowAtIndexPath after a tap).
My problem is now that I would like a few pixels vertical space between my cells. Using the above approach will make the rounded black cells be displayed "back to back".
Is there a way to add the vertical space between the cells or is there a completely different approach I can take to obtain the desired look of my cells?
Thanks in advance.
In order to display a space between cells and avoid the "back to back" issue that you are having you can add a UIView with the the following frame CGRectMake(0, 0, 320, 1) and the background set to a light gray for the standard cell separator or if you just want some padding you can make the background clear.
Personally I like to use interface builder but you can of course do this programmatically.
UIView *cellSeparator = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320 ,1)];
[cellSeparator setAutoresizingMask:UIViewAutoresizingFlexibleLeftMargin |
UIViewAutoresizingFlexibleRightMargin |
UIViewAutoresizingFlexibleWidth];
[cellSeparator setContentMode:UIViewContentModeTopLeft];
[cellSeparator setBackgroundColor:[UIColor lightGrayColor]];
[cell addSubview:cellSeparator];
[cellSeparator release];
The reason I set the cellSeparator at the top of the cell is because the effect is really for the cells that fall in between the first and last rows. Also it is important to set the autoresizingMask and the contentMode to make sure the cell separator adjusts properly when you make size changes to the UITableViewCell. If you have any elements in the cell that start at x=0 y=0 of you will need to move them down the height of the cell separator plus perhaps some additional pixels for padding so that the separator doesn't run through any elements with in the cell.

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