When you use the built-in styles (subtitle, right detail, etc) for UITableViewCells, you can access the text labels very easily with textLabel and detailTextLabel which are properties on the UITableViewCell, no matter which style you choose. I used this to my advantage to implement reusable code that allows me to apply specific styles to all of my static cells. But now I want to convert them all to a custom style cell, but with this style I still will only have two labels. My question is, is it possible to manually set the textLabel and detailTextLabel properties for a custom cell? If so, I would not have to change my code, I would just have to simply set the label properties. Otherwise, I'm going to have to change all of my code to target each individual label for each individual cell which will be really messy.
For an example of what I'm doing, I have a method that accepts in a UITableViewCell and in that method I can enable or disable that cell, which changes the labels text colors to black or light gray as appropriate. If I can't access the textLabel and detailTextLabel properties, I'm going to need to add in if statements to compare the cell parameter to my cell outlets to know which labels I need to change.
You sure can! Just implement the getters for the labels to redirect to your custom cell's labels.
- (UILabel *)textLabel {
return self.myCustomCellTextLabel;
}
- (UILabel *)detailTextLabel {
return self.myCustomCellDetailTextLabel;
}
For people using Swift:
var textLabel: UILabel? {
return myCustomCellTextLabel
}
var detailTextLabel: UILabel? {
return myCustomCellDetailTextLabel
}
In custom cell, you have to add all the views in contentView. That's the designed way, and using of existing textField, and detailTextField is not recommended because it may cause undefined behavior by built-in layout logic. (I haven't used them. They may work well. But I will not take the risk)
If you want to avoid patching all existing code, you can try subclass and overriding the properties to labels which created by you.
#interface CustomCell1 : UITableViewCell
#end
#implementation CustomCell1
{
UILabel* _your_custom_label1;
}
- (UILabel*)textLabel
{
return _your_custom_label1;
}
#end
Related
I want to use subtitle style of table view cell (not the custom one), and also I need to have an UISwitch in the right side of the cell.
if the name of the cell is TitleCell
I know I can add a UISwitch programmatically to it by using this line of code:
TitleCell.accessoryView = UISwitch()
But can I have access to this UISwitch and using it as an outlet and giving it an action?
Thanks for your help in advance
You can give an action to the switch programmatically by calling addTarget (see UISwitch: Swift 3: Programmatically ).
Also consider moving to a custom cell xib/class. It is not hard to set up, but then you have full control over what is there and how it is laid out.
After assigning the switch to the accessory view you can access it with
if let mySwitch = TitleCell.accessoryView as? UISwitch {
// it's the switch, you can use it.
}
However you are encouraged to design a custom cell with an outlet by subclassing UITableViewCell
And please conform to the naming convention that variable names start with a lowercase letter.
I have a simple application which contains a few UITableViewControllers in a UITabBarController. The last UITableViewController is called the More tab and it's a static UITableView. I have designed everything in Storyboard.
Within the More UITableView, I have 4 sections. Within section One, Two and Three, I have 2 basic UITableViewCells. That works well. Within section four, I have 11 basic UITableViewCells. I'm populating the cell titles within Storyboard. I have decided to slightly modify the UI so that section 4 contains a small image and the label.
To do this, I have used Right Detail as the style of the UITableViewCell because it allows you in the inspector, to specify an image.
The problem at the moment is that the image looks just too big.
I have the image in the view, but the size inspector is greyed out.
Without using a custom UITableViewCell (because everything works in this way; just the image is too big), how can I specify the size of the UIImageView? And where do I specify that?
You can create a UITableViewCell subclass and set it to your static cell within storyboard, e.g.
#interface MyCell : UITableViewCell
#end
#implementation MyCell
-(void)layoutSubviews
{
[super layoutSubviews];
//TODO: adjust self.imageView
//self.imageView.contentMode = ...
//self.imageView.frame = ...
}
#end
Or, you can click on that imageView and change it's Mode to Center from the inspector and set an image with right sizes that you want to display.
I want to customize a cell in my UITableView subclass. But I cannot figure out is there any way to do it without defining itself dataSource, because it's obviously override external dataSource.
So basically I want to be UITableView dataSource without rewriting this property.
I have already come up with some dirty workaround. I'm reloading the -setDataSource: method to keep UITableView dataSource itself and save incoming data source into an internal variable for passing the requests to it.
You only need to override cellForRowAtIndexPath: and make your cell modifications there. The datasource will populate the cell as usual.
- (UITableViewCell *)cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//Calling super will let the datasource methods be called
UITableViewCell * cell = [super cellForRowAtIndexPath:indexPath];
//Do whatever to the cell here
return cell;
}
You can customize your cell in one of two ways: code or interface builder. The tableview datasource is the DATA you want to show, it has nothing to do with the presentation of that data.
What do you want to customize about your tableview? Changing fonts, font colors and background colors are easy to do. If you want to add additional ui elements, like images, more labels, then the quickest way is to use Interface Builder.
I want to remove specific views from my UITableViewCell based on some condition, for example:
if (!model.isThumbnail) {
// remove thumbnail UIImageView
[cell.thumbnailView removeFromSuperview];
}
but this will remove UIImageView from all following cells as well..
Is it possible to remove it only per one specific cell (without creating several different cells)?
Thanks!
Since UITableViewCells are reused somewhat automatically, removing individual views from cells would be problematic. Say that you're using two cell layouts, one, layout1, removes view1, the other, layout2, removes view2. Now if a cell is initially configured for layout1, view1 is removed. The next time it gets reused, it gets reused for layout2, so view2 is removed and view1 was removed the last time, so now it's missing both views.
As implied in CEAFDC's answer, a better approach might be to hide (and subsequently show) those views that aren't necessary.
IMO, a better approach would be to use completely different cell layouts (you can even use the same sub-class, just different use different prototypes in the storyboard) and create whichever layout you need at the time.
Maybe you can add a tag to the specific cell...
Can you show how you create the cell? or tell why you need to remove it?
Not sure if I understand your problem, but I think this would solve:
if (!model.isThumbnail) {
cell.tumbnailView.hidden = YES;
} else {
cell.tumbnailView.hidden = NO;
}
or
cell.tumbnailView.hidden = !model.isThumbnail;
try like this,
if (!model.isThumbnail) {
// remove thumbnail UIImageView
[cell.thumbnailView removeFromSuperview];
} else {
if there is no thumbnailView on cell {
// create thumbnailView and add to cell
}
}
But anyway this isn't good solution.
can someone please explain why you should use viewWithTag to get subviews (e.g. UILabel etc) from a cell in dequeueReusableCellWithIdentifier?
Some background info: I've got a custom UITableViewCell with a couple of UILabels in it (I've reproduced a simple version of this below). These labels are defined in the associated NIB file and are declared with IBOutlets and linked back to the custom cell's controller class. In the tableview's dequeueReusableCellWithIdentifier, I'm doing this:
CustomCell *customCell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier:#"CustomCellId"];
if (customCell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"customCell" owner:self options:nil];
for (id oneObject in nib)
if ([oneObject isKindOfClass:[CustomCell class]])
customCell = (CustomCell *)oneObject;
}
customCell.firstLabel.text = #"Hello";
customCell.secondLabel.text = #"World!";
return customCell;
Everything works fine. However from the tutorials I've seen, it looks like when changing the labels' values I should be doing this instead:
UILabel *firstLabel = (UILabel *)[customCell.contentView viewWithTag:555];
firstLabel.text = #"Hello";
UILabel *secondLabel = (UILabel *)[customCell.contentView viewWithTag:556];
secondLabel.text = #"World!";
(The labels' tag values have been set in the NIB).
Can someone tell me which method is preferred and why?
Thanks!
viewWithTag: is just a quick and dirty way to pull out child views without having to set up IBOutlet properties on the parent, or even without having to create a UITableViewCell subclass.
For very simple cases this is an acceptable solution, that's what viewWithTag: was intended for. However if you are going to reuse that cell a lot or you want it to have a more developer-friendly interface then you will want to subclass and use real properties as in your first example.
So use viewWithTag: if it's a very simple cell you designed in IB with no subclass and with just a couple of labels. Use a cell subclass with real properties for anything more substantial.
I've realised that it's useful to retrieve elements using "viewWithTag" if the elements were added to the cell programmatically (i.e. not defined in a NIB and hooked-up via IBOutlets)—this prevents multiple labels etc. to be created for each instance of the cell.
For me , viewWithTag is a God given. First of all : treating all views in a loop like taskinoor said is really easy. Also , I personally prefer this way because if I take a look on the code and want to see what happens with a view , I simply search for the tag. It's used everywhere the view is handled. Opposed to the xib approach where you have to look in the code and xib too. Also , if you have an offscreen view in a xib , you might oversee it.
I found a lot of xibs made by other programmers that were FULL with lots and lots of views. Some hidden , some offscreen , couldn't tell which is which since there were all overlapping.
In those cases , I think xibs are bad. They are not easy to read anymore.
I prefer everything made in code.
But if you decide to work with tags, remember to avoid hard-coding any tag. Instead make a list of #define definitions to keep the code clean and readable.
I always hook subviews to properties of my UITableViewCell subclass via IBOutlets, as you have done. I can't think of any good reason to use viewWithTag.
From UITableViewCell Class Reference: "The table view's delegate in tableView:cellForRowAtIndexPath: should always reset all content when reusing a cell." Keep it simple, clear out the content view. This makes no assumptions about custom cell classes, no casts, no class inspection:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellId];
if (cell != nil)
{
NSArray* contentSubViews = [cell.contentView subviews];
for (UIView* viewToRemove in contentSubViews)
{
[viewToRemove removeFromSuperview];
}
}
viewWithTag: allows styling without creating a custom subclass of UITableViewCell.
You can assign a tag and reuse identifier to a prototype UITableViewCell in Interface Builder, then dequeue and modify the view with that tag within the implementation of your UITableViewController, without creating a custom class for that cell or creating IBOutlets for the cell's subviews.
In some cases, the simplicity of a cell makes a custom class feel like overkill. viewWithTag: allows you to add custom text and image to a cell in the Storyboard, then set those customizations via code, without adding extra class files to your Xcode project.