Stop UITextField resizing when setting text - ios

I have a view setup with 4 UITextFields laid out and constraints setup so that it's looking great on all devices and working as expected. I have an issue where by if I set the text using TextField.text = #" some long text "; or [TextField setText:#"some long text"]; it causes the textfield to expand its width to fit the length of the text and then because of the constraints the other textfields resize too.
How can I stop the textfield resizing ? What I would like is the field to stay the same and the user to be able to just scroll the text If they want to get to the end?
Thanks

You just need to change the constraints. Give the UITextField an explicit internal Width constraint (or use constraints to set or limit its width in some other way) and then things will behave as you desire.
Remember, in general all aspects of a view's size and position must be unambiguously configured by its constraints. Right now, however, your text field has no Width constraint, so its width is based on its text contents (that is, it uses the intrinsic content size to obtain its width). Omitting the Width constraint is not illegal, which is why Interface Builder did not complain when you set up the constraints - but it is legal only because there is an intrinsic content size that supplies a width, and thus it does mean that the width changes if the internal text changes. If that isn't what you want, then don't do that - supply an explicit Width constraint instead.
(Similarly, a text field has an implicit height of 30, which is why you do not have to give it a Height constraint. This height does not change with the text contents, because, unlike a UILabel, a text field does not wrap its text onto multiple lines.)

Related

Determine width of UITextView in heightForRowAtIndexPath with auto layout

A rather convoluted problem, looking for an elegant solution:
A UITableViewCell subclass has a UILabel on the left and a UITextView on the right. Both label and text view have dynamic content. I am using the text view rather than another label because I need the address link recognition.
The label has a higher compression resistance than the text view, so that its right edge will expand towards the right as needed (up to a certain limit). The text view's width will in turn be compressed. The text view is set to word wrap to expand downward.
Because a text view is a itself a UIScrollView, the normal automatic dimension mechanism of a dynamically sized table view cells view will not work (i.e. using UITableViewAutomaticDimension). Thus, I tried to implement heightForRowAtIndexPath. To determine the necessary height, I thought just need:
The text in the label, plus its attributes
The text in the text view, plus its attributes
The width of the table view (as it is "plain" rather than "grouped")
With this information, I reckoned, I can use sizeThatFits on helper objects to determine the necessary height.
However, I am reluctant to hard-code the horizontal margins between the label and the text view into my size calculation, so theoretically I additionally need NSLayoutConstraint outlets for
The left margin of the label to its superview
The max allowed width of the label
The horizontal distance between the label and the text field
The right margin of the text field to its superview
This seems really insane! While I was writing the implementation of this, I asked myself if there is not an easier way to accomplish the same. (That's why I did not yet write the code to post here.) After all, the only hard problem here is how to get the available width for the text view, but the way to getting there seems unduly complex.
Any ideas for a concise, elegant solution?
Side notes: This has to be calculated before the cell is rendered to be displayed. Also, setting the text view's scrollingEnabled to false produces weird results when using sizeThatFits.

Stop UITextField from expanding horizontally

I have a UITextField positioned in a view next to a button. It has a trailing constraint of 8 to the button (which has a trailing constraint of 8 to the superview) and when I type long text in it, it simply scrolls along, which is I want. However, in order to retain the text typed in the field if the view is switched to another one (it's in a tab controller), I save the text in a holder variable and when it switches back to that view, I set the text in the field to the saved text.
The problem is that this causes the field to expand horizontally if the text is long enough, sometimes pushing the button off-screen, even with the trailing 8 constraint. I have tried to save the original frame of the field in a holder variable, and then after setting the text, set the frame to the saved original frame like so:
fieldFrame = messageField.frame
println(messageField.frame.width)
messageField.text = holderMessage
println(messageField.frame.width)
messageField.frame = fieldFrame
However, the field still expands, and it printed out 502.0 twice. My current thought is that the frame hasn't registered the change in width after the setting of the text in time for the println, but I'm not sure if this is correct.
Also, I've read some similar questions that suggested using a width constraint. If I use a less than or equal to width constraint on the field, will it still expand if on a device that's thinner? That is to say, since I'm currently using an any width and any height storyboard, it's wider than, say, an iPhone 6. So if I set a less than or equal to width constraint on the current width of the field, it seems possible that the field can still expand on a smaller device and not break that constraint.
Is there a better way to do such a width constraint? If not, how else can I keep the field from expanding and pushing the button offscreen?
Here's the problem. The text field has a tendency to size itself horizontally to its contents. The button has a tendency to size itself horizontally to its contents. Thus you have an ambiguity: those tendencies have the same priority, so the runtime doesn't know which one to collapse as the text field's text gets too long.
The solution is to adjust those priorities. You must lower the horizontal compression and hugging priorities for the text field - one point lower should be sufficient. Now the button will have a stronger tendency to match its own size to its contents, and the text field will clip its contents.
You can also lower the Content Compression Resistance programmatically (this also works if you are using a UIViewRepresentable in SwiftUi):
uiTextField.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
For more info on this topic please refer to:
https://medium.com/#dineshk1389/content-hugging-and-compression-resistance-in-ios-35a0e8f19118
Selecting the Text view, then within Size inspector:
1) Set "Layout Margins" to "Fixed".
2) Under "Content Compression Resistance Priority", set the "Horizontal" to be "Low (250)".

UILabel max height with AutoLayout

I have a multiline UILabel inside a custom keyboard extension. I want this label to grow to fill the content up to a certain height, at which point I want it to just cut off the rest of the text.
Because the keyboard has different heights depending on the device and orientation, I can't just set a simple less than or equal height constraint.
What I tried was to constrain the bottom of the label to the top of the buttons below, with a greater than or equal constraint. This works to a certain extent, but causes the keyboard to grow in size as opposed to the label being forced to cut off its text.
How would I force the label to a max height, without directly using a height constraint on the label?
Put the label in a UIView and constrain the view's height to less than or equal.

Allow UILabel to grow dynamically using auto layout

I have a label which is going to contain a big description. I want the label to continue growing on new lines. In the image, its the label which starts with event_venue.....
The even_venue.. label has 3 constraints for now:
Vertical space with eventt_title
a horizantal space with the leading of the superview
a width constraints which defines that the label width is always less than the superview.width.
What I want to acheive is to make the event_venue.width less than superview.width, but if it has more text, it should display in new lines. Is this possible using autolayout?
This are possible steps which can create expandable UILabel
Set layouts for UILabel fixing its position
Set number of lines = 0
Set content vertical compression resistance to 1000 (this will allow text to push the label)
Since you want UILabel to expand you cannot give it fixed height constraint or its parent fixed height constraint. Sometimes depending upon condition giving height constraint is necessary to avoid error then you need to set its priority lower than vertical compression resistance
Yes, this totally is possible. I see answers here that are close to solution but not complete. Here is a solution which works with auto layout in Storyboard, no coding of sizeToFit or anything. Your modified steps would be:
Vertical space with eventt_title
A horizontal space with the leading of the superview
A horizontal space with the trailing of the superview
Set UILabel's Line Breaks as Word Wrap.
Set UILabel's lines property as 0.
I have solved a similar problem. I had to make a label that had a variable amount of text. Here's what I did:
In the storyboard, place your label with the origin where you want it.
In the Attributes Inspector, "Label" section, set the Line Breaks = Word Wrap
Fill the label with random placeholder text to the maximum shape you want. For example, if you wanted to fill the whole width and have room for a maximum of three lines of text, you could do:
abcdefghijklmnopqrstu
abcdefghijklmnopqrstu
abcdefghijklmnopqrstu
In the code, set the text of the label using setText:
[self.myLabel setText:#"MyLabelText"];
This did it for me. Your situation may be a little different in that I wasn't changing the width of the superview and it sounds like you might be. But if the width constraint is set on the label then I would expect this to work in your case, too.
I had a similar question about label resizing, and the answer that I found that was useful to me is here: UILabel Auto Size Label to Fit Text. This is a good starting source for code on how to resize your label programmatically.
I would recommend that you also add a horizontal trailing auto layout constraint from the label to the edge of the superview. Do that and you can then get rid of your current width constraint.
AutoLayout facilitate you for orientation purpose. I don think it will give you automatic expansion. You have to define label with width and height completely, otherwise you will see dots at the end of label. So you may use UITextView expanding it all over the screen. And set textView.backgroundcolot = clearColor.

Multiline UILabel with auto layout does not work

I'm trying to set constraints to get a multiline label in a static table view cell, but apparently this does not work for me, the label is still in one single line. I've set the numberOfLines property to 0 and also the height constraint to greater than or equal. And I'm setting the height for the cell correctly in tableView:heightForRowAtIndexPath. Please have a look at my screenshot to see the settings in IB.
In the comments above you mentioned you're not currently setting preferredMaxLayoutWidth. This property tells your label that it should lay out its text over the width of that property's value. In UILabel.h:
If nonzero, this is used when determining -intrinsicContentSize for multiline labels
In other words, if you don't set that, the label's intrinsic content size is whatever width the label needs to draw its text. If you set this property to the label's bounds, it will start drawing on the next line (or else it will cut the text off if numberOfLines is 0).
In your case, I would probably do that in tableView:willDisplayCell:forRowAtIndexPath:.
You can set the preferredMaxLayoutWidth in code, but when designing your user interface in storyboard, you still see a long one-line label that gets cut off at the edges. An alternative is to manually insert line breaks anywhere in your text right within the storyboard using Option-Return. You then just set the number of lines to more than your text will fit. Then select your label, hit Cmd-=. This will calculate the intrinsic content size for your label with the line breaks exactly where you want them to be.
Theoretically, I think setting the preferredMaxLayoutWidth is the more correct way to go about this, especially using Autolayout. However, I found it more practical to use the method I described above because it lets you see the layout at design time right in the storyboard, and you have total control of your line breaks. This usually works better for labels with text that don't change often. If you are dynamically changing the label text, setting preferredMaxLayoutWidth is the preferred way.

Resources