TableView calculates wrong height for dynamic width&height label - swift

I've read multiple threads about this but I've found no solution yet.
I'm making a chat-like application
The app has a TableView that has dynamic height cells in it.
A cell consists of a view and a multiline label in it.
If the label has more characters than >250 it gets shortened with an ending "... see more"
Now the problem is that sometimes the label gets cut off.
I played a little with the Line Break setting of the label, and after changing it to Character Wrap the label shows its full text.
Left picture: Character Wrap - - - Right picture: Word Wrap (I need this)
As you see on the right picture, the "Bt... See More" gets cut off..
I realised that if I set the label's width or the view's width to a fixed size then the problem gets solved: So maybe the problem's root is in the bubble view's leading constraint:
Align leading to Superview
Constant: 0
Priority: 1000
Multiplier: 0.25
(This is needed so that the bubble view expands maximum to 75% of the superview)
I made a GitHub repo for this:
https://github.com/krptia/chatBubbleTest
Help please!
Anyone?

SOLUTION
I figured out that if I set the bubble view's leading constant the following:
Align leading to Superview
Constant: 0
Priority: 1000
Multiplier: 0.25
In order to set the maximum width to 75%, the label inside wraps incorrectly.
SO I deletet the leading constraint and instead of that I maximize the width via aspect-ratio!
If I use aspect-ratio 2:3
Then I achieve the same outcome, but with the label wrapping correctly!!
Yay
SOLUTION 2.0
Okay, now I have figured out that the bubble view's leading constraint's second item (SuperView.Trailing) was Relative to Margin
After unchecking it, the problem gets fixed, so I don't have to use aspect ratio! Yay
BUT PAY ATTENTION
Because using Line Break: Word Wrap also causes some problems.
Sometimes it tries to break the text into a new line (minimum 2 words) but if the cell was reused then the app might calculate wrong height for the view.
First picture: Word Wrap - - - - - - - Second picture: Clip
Maybe this issue can be fixed with layoutIfNeeded() or i don't know. Clip is fine for me
UPDATE (2019.03.27)
Umm.. I realised that the problem occurs still... I don't understand why.
Still trying to figure it out..

Related

Auto Layout TextField. Center, top

I try to understand auto layout. I have a Text field with 3 constraints:
- Align Center X to: Superview
- Top Space to: Superview 50
- Width Equals: 150
I have a warning: Equal constraints may cause clipping
If I change to
- Width Greater Than or Equal 150
I have the warning: Width and horizontal position are ambiguous.
I am confused. In fact, those Constraints work well for a button or a label.
- Why is it different for a TextField?
- How to position a TextField horizontal center, top 50, and width 150?
(It seems that I have to add a leading and trailing Greater Than or Equal. That seems redundant to the Width Greater Than or Equal 150. That works to silence the warning but that seems a solution too complicated and redundant. is that right?)
It's because UILabel and UIButton adjusts its size according to its content. In this case, you need to specify a proper width or you can give a leading and trailing anchor with the desired padding.
Here's is how you can resolve your constraint issue in this particular case. Give the text field the following constraints:
50 points from the top.
Leading from the super view with padding.
Trailing anchor from the super view with padding.
The last two anchors can be replaced with these two constraints:
Width constraint for the text field.
Centre horizontally to the super view.
Here's how you achieve this on a story-board:
I just checked this on:
Xcode 11.2.1
Xcode 11.4.1
The warning shows on 11.2.1 but does not show on 11.4.1
In my view, even though it is a valid warning, it was a silly one and appears to have been removed in the version update.
If you want a label to have a width of 150, of course you know the text will be clipped if it is too long. There is no way around that for a single-line label, unless you allow it to expand outside the bound of the window.
Again, that's a valid warning, but that may be exactly what you want.
If you want a text input field to have a width of 150, the text will scroll when you input too much to fit.
So, why the warning on a text field? No idea. That probably could be considered a bug.
You can get rid of that warning by giving your Width: 150 constraint a Priority: 250. Just single, quick test shows that the field width will remain at 150 even when typing too much text. But... I'd hate to rely on that assumption, and if the field width / leading / trailing etc is related to any other UI elements, I wouldn't count on it not causing other layout issues.
I would say (my opinion only) this is an IB warning that is safe to ignore.

Label width not grown according to content of label

label width is not increasing according to content in table view cell
Please check the attached image for detail
You need to put below constraints to the UILabel instead of leading Constraints.
Why this happens so ?
As the leading is not defined flexible, It will choose the constant value and therefore it will by default will leave space equal or greater from leading.
If we set leading with safe area it will increase width as the text expand till it reaches the safe area line.
Hope this works !!!!
Make constraint >= 20(some constant) to Safe Area and it should work fine.

Expanding UITextView inside a Stack View with scrolling enabled

I am trying to achieve something with Auto Layout and Stackview. I have a Vertical Stackview with a UIView, UITextView, and UIView in it as shown below.
I have checked out the previous answers here but couldn't find a clean solution to achieve this.
The UITextView is editable and must expand as the user types in it - for this I have disabled the scroll for the UITextView in the IB. I also have a height constraint set on the UITextView set to "Greater than or equal to" 10 and number of lines set to 0, so that the UITextView takes the intrinsic height at run time while the user types. I also want the expansion of the UITextView to continue until the UIStackView bottom edge reaches the Keypad accessory's top edge. I have been somewhat able to achieve the expanding UITextView part with my stack view pinned to the top, trailing, and leading edges of the Superview but I keep getting an error that the stackview needs Y position or height which is understandable but if I give it a fixed height or bottom constraint then the UITextView simply won't expand.
I also am not sure how to stop the expansion of the UITextView when it reaches the top edge of the Keyboard accessory view.
The code that I have so far is
let allowedHeight = self.view.frame.height - (self.keyboardHeight! + self.accessory.frame.height)
Basically find the allowed height in the view frame by subtracting the keyboardheight+Accessory view height. This calculation happens correctly. Next I do this (inside textViewDidChange) in hopes that just enabling/disabling the scroll on the UITextView would work but it clearly doens't since the whole text view then weirdly jumps up and down with every key stroke.
func textViewDidChange(_ textView: UITextView) {
if stackView.frame.height >= allowedHeight{
textView.isScrollEnabled = true
}
if stackView.frame.height < allowedHeight{
textView.isScrollEnabled = false
}
}
What is the best way to achieve what I am looking to do?
Couple notes...
I think you'll be better off setting the Max Height of your UITextView rather than of your UIStackView. The Text View will expand / contract based on its content, so you can set a <= height constraint.
Calculate the "elementsHeight" - the vertical size used by your top and bottom views, plus any spacing - and set the "max text view height" to the view height minus elementsHeight ... and subtract keyboard height when visible.
Update the text view's height constraint constant when "max text view height" changes.
Then set up an Observer for the text view's .contentSize ... and enable / disable scrolling based on .contentSize.height compared to "max text view height".
Needs a bit of hoop-jumping, to make sure you update sizes when subviews are laid-out, and to make sure you don't get in a recursion loop.
This is how I set it up:
The initial height constraint on the text view is <= 40 - but that doesn't really matter, as it will be changed via code every time the views layout differently.
I put up an example on GitHub -- it works, but is really just a starting-point. Take a look if you're interested, and pick it apart. https://github.com/DonMag/ExpandingTextView

Why is my UITextField being cut off at the trailing edge?

I'm trying to learn Auto Layout and playing around with various view combinations. I have various views containing other views, but the one I'm having trouble with is one that contains a label and a text field. They are set up like this:
There are several constraints set up on these, such as center Y alignment between the label, text field, and parent view, 0 leading edge for the label, and a hard coded value (12, but irrelevant) for the trailing edge of the text field. I had initially had it as a 0 trailing edge, aligning it with the parent container. However, the right edge of the text field seems to be cutting off and I have no idea why... I Started increasing the distance, thinking that may be there's a margin issue, but nothing seems to help!
Would love any input.

UILabel Text Not Wrapping

I am working on a Swift project with Storyboards where I want text to wrap in a label. In the old Objective-C version where I did not use a Storyboard I used the following settings and things worked perfectly.
Here are the settings for Swift
I have been reading about the potential auto layout issues with preferred width settings. I currently have them set to auto layout and the label itself is set to a width of 560. I've added a constraint to keep the label 20 pixels from the trailing superview and while I thought this would work I still cannot get the text to wrap. The dimension settings are below.
Can someone explain how to get the text to wrap?
First, the good news: You have set the label to 2 lines and Word Wrap. So it can wrap. Excellent.
Now you must make sure the label is tall enough. Either give it no height constraint, or give it a big enough height constraint that it can accommodate two lines.
Finally, you must limit its width. This is what causes the text to wrap. If you don't limit the label's width, it will just keep growing rightward, potentially continuing off the screen. The limit on the label's width stops this rightward growth and causes the text to wrap (and the label to grow downward instead).
You can limit width in several ways. You can have an actual width constraints. Or you can have a leading constraint and a trailing constraint, to something relatively immovable, such as the superview. And there is a third way: on the Size inspector (which you do also show, at the bottom right of your question), set the Preferred Width (it is shown at the top of the Size inspector): this is the width at which, all other things being equal, the label will stop growing to the right and wrap and grow down instead.
Declare your UILabel programmatically and give
yourUILabel.contentMode = .scaleToFill
yourUILabel.numberOfLines = 0
yourUILabel.leadingMargin(pixel: 10)
yourUILabel.trailingMargin(pixel: 10)
This worked for me.
Your text will wrap if you have provided lines number more than 1. However you may not be able to see it wrap if the label height is not enough to show the content. I suggest you to remove the height constraint or increase its value.
In case this helps anybody: I had followed the advice given here to fix my label not wrapping to two lines but nothing worked. What worked for me was I first deleted some of the relevant constraints in storyboard (I'm using auto layout) and saw that the label wrapped properly. I slowly added back the constraints I needed and everything still seems to work fine. So deleting and remaking your constraints may help.
What fixed this problem was changing the label type to "Placeholder" under Intrinsic Size in IB. When I changed this the text wrapped and the warnings went away.
As I see you interface builder. There are two problems. First one is with your constraints, and another one is with the property.
You gave it a fixed height which is wrong while line wrap. You need to make the auto-resizing label, i.e. remove height and add the bottom constraint or simple remove height depend on your situation. Your text is moving to the next line, but due to fixed constraint, you can't see it.
You enable the option to clip subviews which is wrong as it cuts your view and you are unable to view wrap word.
Add a new case:
DO NOT add constraints to your label with a TEXTVIEW, or the label will expand to right without limitation.
In my case i set my parent stackview alignment from center to fill and set UILabel to
label.textAlignment = NSTextAlignment.right