I have a simple UITableViewCell that contains UIImageView and 3 UILabel's. Here, I provide a normal look of the cell to understand the problem deeply:
As you noticed, the description label can be long, so I set numberOfLines to 0. But the problem occurs when that description is empty or small. Cells start to overlap each other. Here is how it looks when the description is empty or small:
If you noticed, pictures overlap each other. The constraints I gave to views are the following:
UIImageView: Leading to superview, width and height, center vertically
BookName(bold label on top): top and trailing to superview, leading to UIImageView
AuthorName(orange label): top to BookName,trailing to superview, leading to UIImageView
Description(gray label): trailing and bottom to superview, top to AuthorName and leading to UIImageView(book image)
I also provided Content Hugging and Compression Resistance Priorities. I provided them only for UILabel's. I set the smallest for description label in order to it grow and shrink.
What I've done to solve the problem?
I realized that if a description is empty, the cell becomes smaller. In other words, labels decide the size of the cell. Also, considering the fact that UIImageView only gets centered vertically, I thought that my constraints are incorrect. So, I decided to get rid of centering vertically the UIImageView. I set top, leading, width and height constraints only for UIImageView. Other constraints were the same as above. But it didn't help, here is the result:
As you see, UIImageView gets out of cell boundary. I thought that it happens because I don't provide bottom constraint for UIImageView. But I provide it for description. So, the next try was actually providing that bottom constraint. So, I provided top, left, bottom and width constraints for UIImageView. I left other constraints the same. Initially, the result was surprising to me. Here is how cells look when there is no description:
Seems like, everything is good(anyway, the image is too small, it tries to fit cell size, that is controlled by labels), but after scrolling UITableView, cells are changing their sizes and somehow updates their constraints. Here is what happened:
I also tried to set estimatedRowHeight and automatic dimension, but it didn't help and I don't think that the problem is solved in this way. So, any help is appreciated.
Keep constraints on the Image view as leading to superview, width, height, vertically centered. Keeps constraints on book name and author label as is. Now On the detail label put constraint as top to author label, trailing to superview, leading or left to image view, bottom to superview. For bottom to superview constraint on detail label change relation to greater than or equal to in Attributes inspector. Change constant to a value you need.I suggest increasing the constant and testing till you get the desired result. Start with something around 20 or 30 and test and then increment value to something else till you get the effect you want. At some value of this constant you will get the effect.
Hope this helps.
NOTE: This is assuming that your Book name label and the author label at least have some text. It can fail on other devices, so also use size classes to set different constraints
Related
I have been facing issues horizontally aligning two UILabel and one UIImageView like this:
First label has variable width, can be truncated if long. Second label has fixed width, it should always be aligned to right of UIImageView. It should never go off screen. UIImageView is aligned to right of first label.
I have tried embedding them in horizontal UIStackView but the image + second label always aligns to end of cell. Got the same issue when trying without UIStackView.
Please help.
You can embed both label and horizontal StackView into another horizontal stack view. Then, you'd need to set the dynamic width Label's Content Compression Resistance Priority (you can find this property at the bottom of the Size Inspector), to be smaller in order for it to shrink.
Then on the container StackView (the one that contains all views), you'd need to set constrains to top, bottom, leading to 0 to the superview and the trailing to be greater than or equal to 0, for it to not take all space of the superview, but at the same time not get offset if the content is too wide.
I hope that is clear enough!
I am getting an image from a URL in a tableview cell. The image view is hugging the right top and bottom of a cell in the tableview cell. To the left of the image is text. I want the text to set the height of the tableview cell automatically and I want the image to conform to the size that is set by the text. How would I do that? Right now it is working but when the image is being downloaded, the cell resizes to become much larger because it uses the large dimensions of the image. As a result the cell in the tableview gets really tall. How would I fix this?
I know the issue is because I am using a greater than or equal to constraint between two of my labels as you can see below in the screenshot. But I need that greater than or equal to constraint.
Here is what my constraints look like:
This is what they look like and what I want it to look like:
This seems to be a cell that is laid out more or less as you desire:
The first label has three lines. The second label has four lines. The third label has one line. The first label has a leading constraint and a trailing constraint to the cell content view; the other two labels have their leading and trailing edges aligned to it. There are four constraints from top to bottom, content view to first label to second label to third label to content view.
The image view has its top aligned to the first label top, its bottom aligned to the third label bottom, its leading edge constrained to the first label trailing edge, and its trailing edge constrained to the content view.
That's all.
EDIT Sorry, I omitted a piece of the puzzle. For your use case, the image view's vertical content compression resistance would need to be lower than any label's vertical hugging priority. That says: "Let the labels dictate how tall I can be." Your labels have a vertical hugging priority of 251, so 250 would do.
You have set your constraints for the 3 labels, now for the image view set equal height to your cell(90-95% should do it). So the labels control the height of the cell and then the cell controls the height of the image view.
Edit: I think that you are complicating things. All your cells will have the same height(title,preview, source of 3,4,1 lines respectively), let them set the height, you don't need content hugging priority with the way i am suggesting.
I would use equal widths to set the width for all the items in your cell, the i would set the horizontal centers, for the spacing between constraints you can either use top-bottom constraints or set vertical centers and you are done.
Bare in mind that top-bottom-trailing-leading are NOT always the best choice, sometimes (like this one) can cause headache.
I came across a problem when configuing the cell of UITableView. I add two labels vertically in the content view of the UITableViewCell, and I also add constraints for the top, leading and bottom layout attributes:
I think that the height of the cell can be caculated dynamically as I have set all the vertical layout and with the instrinct size of the label, the height can be inferred.
so, I can not understand the error message that IB told me.
The second problem is that the height of cell appear on the IB is not changed with the constraint I`ve make. If I decrease the bottom constraint for example, and it is the label to change its size to fit the constraint, but not the cell change its height.
If you need to add top , leading and trailing(or width) to the 1st label. Then add bottom ,leading and trailing(or width)for the bottom label. Then add bottom constraint for 1st label to 2nd label.Then by selecting both labels, add equal height constraint.It will solve your problem.
The meaning of this conflict is that when your label content is increasing dynamically, which label's content is needed to give more priority before whom.
More precisely it can be said that if you increase one of the label's content hugging priority i.e. 252 then that label's content increment and size will be given more priority for incrementing it foremost. As autolayout executes according to the priority of constraints, it faces ambiguity in terms of increasing the views of labels if you do not set the content hugging priority.
I'm trying to use dynamic heights in a UITableView with a specific cell layout. Consider the following illustrative representation of that layout:
I have the horizontal constraints working properly (15px from both edges, 15px between them, equal widths) but I'm struggling with the vertical constraints. Here are the vertical requirements for this layout:
The vertical intrinsic content size of both the green and blue rectangles are based on external data which is passed to the cell at the time of creation.
Both rectangles are vertically centered within their superview
There will always be a minimum space of 15px between the top/bottom edges of the rectangles and the respective edges on the superview. In other words, whichever one is taller dictates the height of the superview (i.e. the cell)
To that end, here's what I have constraint-wise so far:
Vertical center constraints for both rectangles
Height constraints of the rectangles equal to or less than the height of the superview minus 30 (i.e. if the rectangle's height is 40, the superview must be a minimum of 70. This theoretically achieves the same effect as setting separate top and bottom '>= 15' constraints while using two less.)
Vertical content Hugging on the superview set to 'required' (i.e. 1000)
The third point is because the second points together only define the minimum height for the superview (yellow), but not a maximum. In theory, if it had a height of 10,000 it would still satisfy those constraints.
My thought is setting its content hugging to 'required' would make the superview as short as possible without violating the other constraints, thus at all times, either the green rectangle or the blue rectangle would be 15 px from the edge depending on whichever was taller. However, the height still seems to be 'stretched out' as seen here...
Note: The views on the inside are properly vertically centered and correctly maintain a minimum distance from the top/bottom edges. The problem I'm trying to solve is restricting the height of the superview to be as small as possible.
It doesn't appear that I'm getting any ambiguous constraint messages (I don't see anything in the logs, but I believe I should be because again <= constraints aren't enough on their own, so I'm not sure exactly how to use the tools to debug this, or to find out which constraint is driving the height.
So, can anyone help?
P.S. To ensure it wasn't something external to the cell, like forgetting to configure auto-heights for the UITableView, I removed the two rectangles and replaced them with a simple multi-line label pinned to all four edges. When I ran it with that, the cell properly shrank in size as expected. I bring that up to hopefully stave off answers suggesting that's potentially the problem.
Reading the requirements you provided I have added constraints shown below:
For demonstration purpose I have used a simple view container instead of a cell. Since inner boxes will have intrinsic content size derived externally, I have taken labels to mimic that.
To reiterate, constraints added are:
Horizontal
Container view(orange) has leading and trailing constraints with the super view.
Inner views has leading, trailing constraints with 15points of space.
Both labels have leading and trailing constraints with 9 points.
Both inner views have equal width constriant.
Vertical
Container view is vertically in center.
Both inner views have vertically center constraint applied.
Both inner views have top and bottom constraints with >= 15 condition.
Both inner labels have top and bottom constraints with their super views.
I set the no. of lines property of both labels to zero so that they can grow at run time.
At runtime I changed the text of one of the label and the box and container grew accordingly.
To refresh your cell height implement heightForRow method and provide the latest height. A typical snippet will look something like this (assuming you have already initialized the cell):
cell.needsUpdateConstraints()
cell.updateConstraintsIfNeeded()
cell.contentView.setNeedsLayout()
cell.contentView.layoutIfNeeded()
let height = cell.contentView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height + 1
return height
Hope this will help.
Ok, so I was going in the right direction with the content hugging, but the correct way to handle this was to specify a height constraint on the yellow view of 0 and with a low priority. I used 100 to be even lower than the default 250. When I did that, the solver tries to get as close to zero as it can while still respecting the other constraints, therefore 'hugging' the content. Still don't know why content hugging on its own didn't work, but that addressed the issue.
I'm trying to use Auto Layout to take advantage of the self-sizing UITableViewCells.
I have one UILabel at the top of the cell and another beneath it. I set the top constraints to be pinned to the top, left and right, and the bottom to be pinned to the top left and right of the upper label.
Now as I go to set the bottom label's final constraint (its distance from the bottom) I set it to 10pt from the bottom of the cell. However this sparks a bunch of Auto Layout complaints. It says I have to make one of the labels have a higher vertical hugging priority. Why is this?
And in the WWDC video, the engineer sets the bottom one to be greater than or equal, instead of just equal. This seems like a poor solution at least in my case, because I never want it to be greater than what I set.
The IB issue you are seeing is due to the fact that the content that you currently have in the labels and all your constraints doesn't fit the UITableViewCell height (it doesn't autosize in IB yet). The autosizing happens at runtime, and setting it to greater than or equal is fine as the code autosizing will find the smallest size that acceptably fits all your content.