I'm using a UITableView with cell style of UITableViewCellStyleValue1.
I'm want to have multiple lines in the detailTextLabel, is that possible? Or do I have to make a custom cell?
You can set cell.detailTextLabel.numberOfLines = 2 to get 2 lines in there. However, I doubt UITableViewCell will lay out the labels as you expect in that case. You may want to subclass UITableViewCell and override -layoutSubviews to position the labels how you want. You can call [super layoutSubviews] and then just tweak the positions of the labels. You'll probably want to use -[NSString sizeWithFont:constrainedToSize:lineBreakMode:] to calculate the correct size for the detail text label.
Alternatively, instead of subclassing UITableViewCell, you could try doing the tweaks in -tableView:willDisplayCell:forRowAtIndexPath:, though if the cell ever decides it needs to re-layout, then your tweaks will be erased. I recommend you go with the subclassing approach.
Edit: BTW, with the subclass approach, all you have to do is change [UITableViewCell alloc] to [MyTableViewCellSubclass alloc]. Since you're not introducing new methods or properties, the variable can still remain typed as a UITableViewCell and you won't have to change any other code.
The detailTextLabel is a UILabel, the word wrapping rules apply just like with a label you create.
http://developer.apple.com/iphone/library/documentation/uikit/reference/UILabel_Class/Reference/UILabel.html#//apple_ref/occ/instp/UILabel/lineBreakMode
EDIT: Just thought, you'll also need to change the height of the cell if the text gets beyond some threshold of lines. probably 2 or 3 is okay.
At least on iOS 11 it works great just adding this line.
cell.detailTextLabel.numberOfLines = 2;
On SWIFT 4.0 and above:
cell.detailTextLabel?.numberOfLines = 0
Unless you never want to have more than 2 lines, do not set numberOfLines to 2 as advices in the comments because it's not an efficient way to code. It's not dynamic. The number of lines might be different base on your screen size, accessibility settings etc. Setting numberOfLines to 0, let the OS use as many lines necessary to display properly your text.
Related
Nowadays fortunately it's trivial to have an iOS table where every cell has a dynamic height. So in the cell vertical constraints ..
---- top of content view
- vertical constraint to
-- UILabel, with, .lines set to zero
- vertical constraint to
---- bottom of content view
Assume the UILabel texts vary greatly one word, 20 words, 100 words,
In the table set
tableView.rowHeight = UITableView.automaticDimension
tableView.estimatedRowHeight = 200 // say
and you're done, these days it works perfectly of course.
However, I had the common situation where you load the table, imagine ten cells.
I populate the UILabel with "Loading..."
Only then - say, a second or two later - do we get the information for the text content. It arrives say a second later and the cell changes the text to "Some long text .. with many lines".
In fact I was surprised to learn it seems UITableView does NOT handle this. The cell in question gets stuck on the original short height.
So, after the larger text is set, I tried all permutations of the usual:
maintext.sizeToFit()
contentView.layoutSubviews()
contentView.layoutIfNeeded()
on the cell, doesn't work.
I tried sending a setNeedsLayout and/or layoutIfNeeded to the table itself, doesn't work.
I thought about .reloadData() on the table itself but - doh - that would again trigger the content being drawn from the server and loaded again, so that's not ideal.
Please note that:
Obviously there are any number of workarounds for the specific example such as not using dynamic data
I am completely aware how to manually animate the height of one cell (like when you "expand" one to show something else when the user taps)
This question is about autolayout and table view - which, thanks Apple, nowadays flawlessly handles completely dynamic cell heights involving UILabels with lines zero.
But what about if the text in such a label changes?
It seems that the table view system does NOT handle this.
Surely there's a way?
When the content of a cell changes the layout (in this case, the height) you must inform the table view that the layout has changed.
This is commonly done with either:
tableView.beginUpdates()
tableView.endUpdates()
or:
tableView.performBatchUpdates(_:completion:)
Why is that not triggered automatically?
I suppose it could be to allow you to do your own animation, or you may want to delay the update, or some other reason that doesn't come to mind at the moment.
Or, it may be due to maintaining backward compatibility?
I don't know. I imagine Apple could tell us...
I am trying to achieve something like this for iOS in Objective C.
The fill in the blanks(UITextField) should be inline, and should be able to have its own inputType.
Also, each View is a type of cell.contentView of a UITableViewCell.
My current approach is to find the length of string and also calculate the wrapping content length to the next line. Calculate the x's and y's for UITextField and add another UILabel after the UTextField
Is there any other approach other than this?
As EmilioPelaez says, this is not exactly an answer to your question, but a suggestion:
You can use a collection view with an horizontal flow for each "sequence" (i.e. UILabel-UItextfield-etc...)
That collection view has 2 kind of cell:
One with a uilabel with the number of line set to "1"
and the correct layout to fit the cell.
Another with a uitextfield and the correct layout
Coupled with:
My current approach is to find the length of string and also calculate the wrapping content length to the next line.
You may be able to easily adjust the width of the different cells, hide a uitextfield (if needed) and display a more dynamic "sequence" (if needed)
This is not exactly an answer to your question, instead it's a suggestion for a different interaction.
I think that instead of using inline textFields, you could use a UILabel with an attributed string, and in where the textFields would be, you add a different character with a different color that you can tap (For example, this character ✚).
When tapped, you can show an overlay with a text input, and once that input is completed, you update the label with the text (still tappable, and with a different color).
I think this answer might also be relevant: Detecting taps on attributed text in a UITextView in iOS
I think your solution of separating the UILabels and calculating their required positions is a good one for versions lower than iOS9, but if you can count on iOS, UIStackView can dramatically simplify the process for you. You can read more about the process in this tutorial:
UIStackView Tutorial
Good luck!
I've got a tableView of type Plain containing one PrototypeCell of Type Custom. The prototype cells class is the default UITableViewCell class, as I'm NOT using any specialized subclass.The problem is, that I simply want to style the textlabels contained within the default UITableViewCell (textLabel and detailTextLabel) by using UIAppearance for iOS7.
I've tried
[[UILabel appearance]] appearanceWhenContainedIn:[UITableViewCell class], nil] setTextColor:UIColor.redColor];
to no avail. I know that the Apple documentation states, that the default labels mentioned above are always created with the default font and with textcolor black. However I expected, that styling the UILabels with appearance should work out. Any ideas regarding that topic?
REMARK: I know it's possible to set the textcolors usingcell.textLabel.textColor = UIColor.redColor, but I want to define the styling once.
If you want to use this two labels, you don't have a Custom cell but a Subtitle cell. And still you can change the properties of these labels in the IB.
Just double click on the labels to change their properties. (Or have a look in ContentView on the left):
I've written a custom GridView (UIScrollView Subclass) and decided to use a standard UITableViewCells as Cells because they have all the functionality I need.
Everything works fine but I've noticed that sometimes I have a thin gray line at the top of a cell.
I actually thought that the UITableView handles the separators of the cells and they actually don't belong to a UITableViewCell but it seems to be that I'm wrong.
In fact I want to get rid of them but I don't know how.
Does anyone has experience with this or is the only way to make a custom cell class with the features of a UITableViewCell?
Here's a screenshot:
After some experimentation, try & error and subview iterating/checking I can tell that the separator is definitely part of an UITableViewCell. Thanks to #Valeriy Van.
The answer to my first question simply is: YES, the separator is
part of a UITableViewCell.
But it is strictly handled by the UITableView and is empty if it is not populated by the TableView.
Now to the lines in the image above:
These are not separators. They just look like that, such a damn coincidence.
They happen when the Graphics tries to draw something at subpixel-precise coordinates.
This can happen, when the coordinates and/or sizes (the frame) of an visible object (the layer of the view) are between two integer values and the GL tries to render it properly.
Due the "overprecise" frame, the Gl tries to interpolate to integer frames or just not round properly.
So it can happen, like in the picture above, that the first line is stretched or the y-coordinate wrong by one pixel.
This can also happen in a UITableView if you return "overprecise" values for cell-heights.
tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
Edited:
Below is a line from UITableView.h
#property(nonatomic) UITableViewCellSeparatorStyle separatorStyle; // default is UITableViewCellSeparatorStyleSingleLine
UITableViewCell, UITableView, UITableViewController designed to work together. And your problem is you try to use UITableViewCell separately. Logically, cells separator is not characteristic of a cell, it's characteristic of a table. That's why separatorStyle is property of UITableView, not UITableViewCell. Well, different approaches are possible, and Apple had chosen this. Look into UITableView.h for how many times 'separator' substring occurs there. Have a look into UITableViewCell.h: UITableViewCell has reference to UITableView. And UITableViewCell coded accurately enough not to crash if _tableView is nil. I think, if _tableView is nil, cell applies same defaults and draws itself with default separator.
What can you do to get rid of separator in you case? If you can't use UITableView in way it was designed, cheat in some way. Try to feed cell with some dumb tableview with properties you need.
How do you add counts inside of a UITableView UITableViewCell like the iOS Mail app?
In addition to DDBadgeViewCell (mentioned by #micpringle), there's also TDBadgedCell.
I tried out both and found TDBadgedCell to suit my needs more, as it puts the badges over the cell's text rather than under it, meaning the badges are visible even for cells with long texts.
The project also seems to be (currently, at least) more active than DDBadgeViewCell. (That being said, there seems to be a bug in the non-ARC version of TDBadgedCell.)
Create a custom UITableViewCell, position the labels where you want them (title, subtitle, count, whatever you need). I highly recommend Matt Gallaghers custom UITableView code - it takes a lot of the headaches out of dealing with custom rows. You'll have to follow Matt Gallaghers steps for customizing the cell.
To get the appearance of the count label as close as possible to your example (mail.app), you'll have to set the UILabel backgroundColor to gray (or whatever color you want it to be), textColor to white, and layer.cornerRadius to something equal to half the height of the label (if label is 20 high, cornerRadius should be 10). This will result in a UILabel with white text, gray background, round corners. Note - this isn't the most efficient method of doing this, but Apple hasn't put up the WWDC session video where they explain the performant method better (I missed that session).
The easiest solution would be to set an UILabel as accessoryView or using a custom UITableViewCell subclass which could be designed using IB.
I'd recommend creating a simple rounded UIView and a UILabel as a subview in it. I'd probably create a UITableViewCell subclass to manage the content.
Definitively the most easy way would be using a ready-to-use class like TDBadgedCell