contentView not indenting in iOS 6 UITableViewCell prototype cell
On further investigation (viewing the subview hierarchy of the cell) Interface Builder does place subviews within the cell's contentView
, it just doesn't look like it.
The root cause of the issue was iOS 6 autolayout. When the cell is placed into editing mode (and indented) the contentView
is also indented, so it stands to reason that all subviews within the contentView
will move (indent) by virtue of being within the contentView
. However, all the autolayout constraints applied by Interface Builder seem to be relative to the UITableViewCell
itself, rather than the contentView
. This means that even though the contentView
indents, the subviews contained within do not - the constraints take charge.
For example, when I placed a UILabel
into the cell (and positioned it 10 points from the left-hand side of the cell) IB automatically applied a constraint "Horizontal Space (10)". However, this constraint is relative to the UITableViewCell
NOT the contentView
. This means that when the cell is indented, and the contentView
moves, the label stays put as it is complying with the constraint to remain 10 points from the left-hand side of the UITableViewCell
.
Unfortunately (as far as I am aware) there is no way to remove these IB created constraints from within IB itself, so here is how I solved the problem.
Within the UITableViewCell
subclass for the cell, I created an IBOutlet
for that constraint called cellLabelHSpaceConstraint
. You also need an IBOutlet
for the label itself, which I called cellLabel
. I then implemented the -awakeFromNib
method as per below:
- (void)awakeFromNib {
// -------------------------------------------------------------------
// We need to create our own constraint which is effective against the
// contentView, so the UI elements indent when the cell is put into
// editing mode
// -------------------------------------------------------------------
// Remove the IB added horizontal constraint, as that's effective
// against the cell not the contentView
[self removeConstraint:self.cellLabelHSpaceConstraint];
// Create a dictionary to represent the view being positioned
NSDictionary *labelViewDictionary = NSDictionaryOfVariableBindings(_cellLabel);
// Create the new constraint
NSArray *constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"|-10-[_cellLabel]" options:0 metrics:nil views:labelViewDictionary];
// Add the constraint against the contentView
[self.contentView addConstraints:constraints];
}
In summary, the above will remove the horizontal spacing constraint which IB automatically added (as is effective against the UITableViewCell
rather than the contentView
) and we then define and add our own constraint to the contentView
.
In my case, all the other UILabels
in the cell were positioned based upon the position of the cellLabel
so when I fixed up the constraint/positioning of this element all the others followed suit and positioned correctly. However, if you have a more complex layout then you may need to do this for other subviews as well.
Indentation not working on Custom UITableViewCell
Indentation isn't the same as adjusting the content view when entering edit mode.
You're right, this seems simple and usually works almost straight out of the box. Typically the only things you need to change are the autoresizing masks of the components you add to the cell. Content on the left should have a fixed left margin, content on the right should have a fixed right margin.
When the cell enters editing mode the content view's size is adjusted to allow room for the editing accessories. If your content has these resizing masks, it will move along with this. Your layoutSubviews method above is quite likely undoing all this by setting the content view back to full width because you are using indentation incorrectly - though I can't be sure of that from the information in the question.
UPDATE
This is a issue (bug?) with constraints in UITableViewCells. You can go back to autoresizing masks by selecting the "File" tab in the storyboard / interface builder screen (if you want to use constraints elsewhere, use a standalone nib for the cell) and unchecking "Use Autolayout":
This arranges your cell content properly.
UITableViewCell editing indentation
Simple way is in your custom cell class - in layoutSubviews
method adjust your cell.view.frame
if (self.isEditing) {
// then shift cell frame to left side
}
else {
// then shift cell frame to right side
}
Reusable UITableView's prototype cell
I don't think you can create a prototype cell and share it between tables in a storyboard, but you can create a prototype cell in a nib and then load that in the ViewDidLoad method and then use that in your table view. It is really quite simple, here is how...
A. add the nib file:
1. Select New File...
2. Select IOS -> User Interface
3. Select "Empty" -> this will add a new file .xib file to your project
4. Drag a UITableViewCell from the object browser into your xib file and customize to your liking
5. Use the Utilities pane to change properties -> editing a nib is very
similar to editing a storyboard.
6. Make sure you name your cell - I chose the name cellFromNib, but you will probably want something else.
B. Load the UITableViewCell in each table's viewDidLoad method:
- (void)viewDidLoad
{
// load the cell in the nib - the nib can only contain this one UITableViewCell
[self.tableView
registerNib:[UINib nibWithNibName:[self @"nibFileNameWithoutExtension"]
bundle:[NSBundle mainBundle]]
forCellReuseIdentifier:[self @"cellFromNib"]];
}
C. De-queue the nib's tableViewCell...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cellFromNib" forIndexPath:indexPath];
// customize your cell here...
}
D. Add a "dummy" prototype cell to your TableView in your storyboard.
Make a segue from this "dummy" cell to the view you want displayed when the cell is selected - make sure to name the segue - I'll call it @"theSegue" for this example. You will reference this segue in your code.
E. Finally, add code to segue from that cell...
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// this is basically what the storyboard does under the hood...
// make sure you have a "dummy" prototype cell with this segue name for each
// tableview that uses this cell
[self performSegueWithIdentifier:@"theSegue" sender:self];
}
If you want to specialize your cell code, create a class that subclasses UITableViewCell
I think that is everything you need.
I would say do not be afraid of doing something like this because, if you are serious about IOS programming, you will learn something new. It really does make for much better reusable code.
indentationLevelForRowAtIndexPath not indenting custom cell
Yeah, it seems like custom table cells don't do this automatically? You need to override the layoutSubviews
method in the table cell class. See this question for how to do this.
This code worked perfectly for me (although be careful if you are setting a custom height w/ the delegate as well, they seem to interfere with each other):
- (void)layoutSubviews
{
[super layoutSubviews];
float indentPoints = self.indentationLevel * self.indentationWidth;
self.contentView.frame = CGRectMake(
indentPoints,
self.contentView.frame.origin.y,
self.contentView.frame.size.width - indentPoints,
self.contentView.frame.size.height
);
}
Edit for iOS8 and later
The above does work for me on iOS, but it causes subtle bugs when trying to autosize the height of the cell as well. There is n easier solution: If you have autolayout turned for the cell just set the left margin of the contentView:
override func layoutSubviews() {
super.layoutSubviews()
self.contentView.layoutMargins.left = CGFloat(self.indentationLevel) * self.indentationWidth
self.contentView.layoutIfNeeded()
}
Related Topics
Swiftui - Animations Triggered Inside a View That's in a List Doesn't Animate the List as Well
Fbsdkaccesstoken Currentaccesstoken Nil After Quitting App
Xcode Version 6.1 (6A1030) - Apple MACh O-Linker Error - Building
Is It Okay to Leave Out Unnecessary Launch Images
iOS Autolayout Multi-Line Uilabel
Locking a Uisearchbar to the Top of a Uitableview Like Game Center
Check If Location Services Are Enabled
iOS Nsattributedstring on Uibutton
How to Manage Cookies with Uiwebview in Swift
Swift - Compressing Video Files
Conditionally Import a Framework (Such as Speech) Based on iOS Version in Swift
Images Not Showing Up When Architecture Set to 64 Bit
Eraser Not Working in iOS Drawing
As3 for iOS:How to Serialize an Array and Then Save It
Error: Cuicatalog: Invalid Asset Name Supplied: (Null), or Invalid Scale Factor:2.000000