Grow TableViewCell height with wrapping Label - ios

I have the following four Labels in a custom TableViewCell which currently look like this:
I have this:
The first, third and fourth labels have their width constraints fixed and maximum number of lines set to 1. The second Label fills the horizontal space between labels one and three.
I would like the second Label to wrap to a maximum of 2 lines and be vertically aligned to the top so that the first line of each label are aligned like this:
I want this:
I have made the background colour of each label grey so that the constraints can be seen.

You can achieve this using self sizing cells. To make that work add those two lines to your UITableview:
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 50
Then in Interface Builder set the following constraints in your Prototype Cell:
Uncheck "Constraint to margins" on all constraints.
Label 1:
top: 10
left: 10
bottom: greaterOrEqual 10
width: 60 (or whatever the actual width is)
Label 2:
top: 10
left: 10
bottom: 10
Label 3:
top: 10
left: 10
bottom: greaterOrEqual 10
width: 60 (or whatever the actual width is)
Label 4:
top: 10
left: 10
right: 10
bottom: greaterOrEqual 10
width: 60 (or whatever the actual width is)
If you set the constraints like this, the cell height automatically gets higher when the second label wraps its text into a second line.

To top align the UILabels, you can either set the margin top constraint of all UILabels to be constant, or set the top align constraints. To set the top align constraints, select the label and ctrl-drag from the label to another. Select top alignment from the popup.
One thing to keep in mind is that for the second label, set the 4 margin lengths to be around 5pt, but do not constrain its width or height like the others.
Maximum of 2 lines can be configured in the right utilities panel after selecting the second label.
To dynamically change the height of the cell is a little trickier. First you should know if the text is long enough to stretch the label into 2 lines and the height of the label. (See Here) If the text is long enough to take two lines, the method will return a height value that is larger than it would normally. Based on this height change, use the following UITableViewDelegate to dynamically change the height of that UITableViewCell:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
Hope this helps.

Related

Multicolumn list with flexible columns width - iOS

I want to create list with two columns. Text in first column should be aligned to left and text in second column should be aligned to right. Space between columns should be constant. Different cases depends on texts length should be covered:
1.
Text 123
TextText 12
Tex 123
Text 1
Te 123456
T 12
Te 1234
Te 1
Text 123
TextText 12
TextTextTextTextText 123
Text 1
Both columns should have flexible width depends on the longest text. They also should have some minimum width so it will not be completely invisible if text in other column will be too long. Whole list also should have flexible width, of course there is some max width and then text in first column should be divided into lines. I don't want to divide into lines text in second column as long as I don't have to.
How to create such list?
I try to use for it two stack views one next to the other. These two stack views I have in my custom control. My custom control is added to container view using xib and have constraints equals to 0 for top, leading and bottom and greater or equals 0 for trailing. To these stack views I add labels programatically and I also set content hugging priority for them (first label has lower priority than second one). One think stil doesn't work, first stack view is as width as first label in this stack view. It doesn't change his width when other labels with longer texts are added. Is it possible to have working solution without calculating stack views width manually?
private void Initialize()
{
_firstStackView = new UIStackView
{
TranslatesAutoresizingMaskIntoConstraints = false,
Axis = UILayoutConstraintAxis.Vertical,
Spacing = 4
};
_secondStackView = new UIStackView
{
TranslatesAutoresizingMaskIntoConstraints = false,
Axis = UILayoutConstraintAxis.Vertical,
Spacing = 4,
Alignment = UIStackViewAlignment.Trailing
};
Add(_firstStackView);
Add(_secondStackView);
AddConstraints();
}
private void AddConstraints()
{
NSLayoutConstraint.ActivateConstraints(
new[]
{
_firstStackView.LeadingAnchor.ConstraintEqualTo(LeadingAnchor),
_secondStackView.LeadingAnchor.ConstraintEqualTo(_firstStackView.TrailingAnchor, 20),
TrailingAnchor.ConstraintEqualTo(_secondStackView.TrailingAnchor),
_firstStackView.TopAnchor.ConstraintEqualTo(TopAnchor),
_firstStackView.BottomAnchor.ConstraintEqualTo(BottomAnchor),
_secondStackView.CenterYAnchor.ConstraintEqualTo(_firstStackView.CenterYAnchor),
_secondStackView.WidthAnchor.ConstraintGreaterThanOrEqualTo(WidthAnchor, 0.25f),
_firstStackView.WidthAnchor.ConstraintGreaterThanOrEqualTo(WidthAnchor, 0.25f),
});
}
You can use UICollectionView to create list with two columns. Space between columns and grid size can be adjusted by changing UICollectionViewLayout.
Implement text adaptive width and height:
Instantiate UILabel
Set the UILabel property to get the text content and font
Calculate the size according to text and font
Use CGSize to set the maximum width you want
Set the frame according to the size
You can see some useful info here
For more details, you can refer to the following doc:
Collection Views in Xamarin.iOS | Microsoft Docs

change hight of the tableView cell does not work

hello guys now I have UITableViewCell should have dynamic height , this cell have 3 labels , I have added them in to stack and I added all requirements
to let tableViewCell be dynamic height
1- The code used for automatic cell height
notifications.rowHeight = UITableView.automaticDimension
notifications.estimatedRowHeight = 150
2- I have set constraints leading and trailing and bottom and top space to the superView.
3- The number of lines for each label is equal zero
this is cell before run
enter link description here
this cell after run https://ibb.co/5YCMpfK
The constraints of your tableViewCell must be like:
Properties of stackView:
Axis: Vertical
Alignment: Fill
Distribution: Fill Proportionally
Spacing: 5 (as per your requirement)
Number of lines of all 3 labels = 0
Check if your stack view doesn't have height constraint.
Check if your labels do not have any height constraint.
Give your stackview top and bottom constraints a specific value and make them greater than equal to topContraint >= 5 bottomconstraint >=5.
Change the property of stack view to Fill proportionally and give spacing according to your needs.

Custom UITableViewCell - adjust UILabel vertical alignment dynamically

I have a custom table cell. It has two labels (title and description), one below the other.
What I have right now is, title label top = topMargin. And description label top = title label bottom + 10.
But in some cases, there will be no description. In such cases, I want the title label to be centered vertically inside the cell. Is this possible? What constraints do I have to set?
A UIStackView makes it easy to do what you want.
Create a prototype cell
add two labels
embed them in a stack view
set the stack view's properties to:
Axis: Vertical
Alignment: Fill
Distribution: Fill Equally
Spacing: 10
constrain the stack view Top/Leading/Trailing/Bottom to 0 to the cell's content view's default margins (or set your own "padding")
set your fixed row height - with default labels + 10-point spacing + top and bottom margins, you'll probably want at least 67
connect the labels to IBOutlets
When you set the text of the labels in cellForRowAt indexPath:, set the description label's .isHidden property to true if it has a description, or to false if it doesn't.
The result (with background colors for clarity):
The result without background colors:

How can you set a UILabel's height to exactly match its font size?

I've got a UI design spec to follow where the spacing between text is precisely specified i.e. here's a spec for vertical spacing in a table view cell:
The problem when using a storyboard and constraints is that when you place a UILabel in the storyboard its height is larger then its contained font size (so you can't for example set a vertical constraint of 6 between the two line in the spec for example, as that would set the UILabels 6 points apart, not the contained text 6 apart).
Here's a diagram to make it clear what I mean:
Here the constraint is 6px. But I want to be able to set the distance between the bottom of the text of Label1 and the top of the text of label 2 to be 6.
By setting a vertical constraint of 6 between the labels, the distance between the text within those labels is greater than 6.
I attempted to solve this by using a custom label:
#IBDesignable
class NoPaddingLabel: UILabel {
override var alignmentRectInsets: UIEdgeInsets {
return UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
}
}
But this doesn't adjust the height of the UILabel in the storyboard despite the #IBDesignable - for example if you drag and drop a UILabel then by default its System font size 17, with a height of 21. If its type is changed from UILabel to NoPaddingLabel its height is still 21.
If constraints are then added there's tones of errors regarding vertical compression and vertical hugging priorities conflicts.
So, is there a way to calculate the height of the UILabel in the storyboard to correspond to the height of its font so that its easier to set exact vertical constraints between text? -
Whats the solution to set exact constraint distances between text, rather than between labels in a storyboard?

Two labels alignment and its constraints

I have 2 labels: the description label (w/ red background) and the results label (gray text)
How do i set constraints for this example in order to have the results label with the size of its content and the description label until the results leadingAnchor? (like i have in the second row)
Objective C
[self.customTextLabel.trailingAnchor constraintLessThanOrEqualToAnchor:self.counterLabel.leadingAnchor].active = YES;
[self.counterLabel.widthAnchor constraintGreaterThanOrEqualToConstant:0].active = YES;
swift
titleLabel.trailingAnchor.constraint(lessThanOrEqualTo: counterLabel.leadingAnchor).isActive = true
counterLabel.widthAnchor.constraint(greaterThanOrEqualToConstant: 0).isActive = true
I have a solution that i think it's ugly.
self.counterLabelWidthConstraint = [self.counterLabel.widthAnchor constraintEqualToConstant:0];
self.counterLabelWidthConstraint.active = YES;
And then after i set the text:
self.counterLabelWidthConstraint.constant = [self.counterLabel sizeThatFits:CGSizeMake(CGFLOAT_MAX, self.counterLabel.height)].width;
The way to do this with auto layout is by using the contentCompressionResistancePriority of the 2 labels. Set the pririty to NSLayoutPriorityRequired for the second label and something lower like NSLayoutPriorityDefaultLow for the first label. Then, as long as the 2 labels have proper constraints anchoring them to their superview and each other, the first label should compress while the second label should not.
You just need to increase the horizontal compression resistance of the right/gray label to be higher than that of the left/red label. This tells the visual layout that, in the event that there is not enough space for both labels, the one on the left will be compressed before shrinking the label on the right. 750 is the default for all views, so just increase the right/gray label's horizontal compression resistance to 751 and you should be good to go.
Swift 5 programatically:
<#label#>.setContentCompressionResistancePriority(.required, for: .horizontal)
Labels with this property will not compress horizontally.
You can set constraints for in storyboard itself. Select Label 1 (red back ground) and label's superview set widths are equal constraint. Select Label 1 and double tap on its width constraint, from the resultant window, you could see Lable 1 width equal to superview with value constant as '1'. change '1' to 0.7 or whichever the percentage you want.

Resources