I have a UITableViewCell which has two UITextFields (without borders). The following constraints are used to set up the horizontal layout.
@"|-10-[leftTextField(>=80)]-(>=10)-[rightTextField(>=40)]-10-|"
Nothing fancy, and works as expected.
As you can see the upper textField has the correct size. The lower textField started with an empty text, and because of the empty text it is 80 points wide. When I type text into the editing textField the text scrolls to the left, it does not change its width.
I don't like that, the width of the textField should adjust while the user types into that textField.
In my opinion that should work out of the box. By implementing a IBAction
for the UIControlEventEditingChanged
event I can confirm that typing actually changes the intrinsicContentSize
of the UITextField.
But well, the width does not change until the textField is no longer the first responder. If I put the cursor into another textField the width of the edited textField is set. That's a bit late for what I want.
These commented out lines is what I tried without any success:
- (IBAction)textFieldDidChange:(UITextField *)textField {
[UIView animateWithDuration:0.1 animations:^{
// [self.contentView removeConstraints:horizontalConstraints];
// [self.contentView addConstraints:horizontalConstraints];
// [self.contentView layoutIfNeeded];
// [self.contentView setNeedsLayout];
// [self.contentView setNeedsUpdateConstraints];
}];
NSLog(@"%@", NSStringFromCGSize(textField.intrinsicContentSize));
}
Does anybody know what I am missing? What could I try to make this work?
Here's the answer in Swift. As a bonus, this snippet doesn't collapse the text field if there is a placeholder.
First things first: in Swift 4, UITextField's intrinsicContentSize is a computed variable, not a method.
Below is a Swift4 solution with a specialized use case. A right justified textfield can resize and extend leftward up to a certain pixel boundary. The textfield is assigned to the CurrencyTextField class which inherits from UITextField. CurrencyTextField is then extended to provide custom behavior for returning the object's intrinsicContentSize, a computed variable. .
The "editing changed" event of the CurrencyTextField instance is mapped to the repositionAndResize IBAction method in its host UIViewController class. This method simply invalidates the current intrinsic content size of the CurrencyTextField instance. Invoking the CurrencyTextField's invalidateIntrinsicContentSize method ( inherited form UITextField ) triggers an attempt to get the object's intrinsic content size.
The custom logic in CurrencyTextField's intrinsicContentSize getter method has to convert the CurrentTextField's text property to NSString in order ascertain its size, which it returns as the intrinsicContentSize if the x coordinate of the CurrencyTextField is greater than the stipulated pixel boundary.
This is what works for me:
What's interesting is that it seems as if it SHOULD work out of the box, given this text from the docs:
My best guess is that the textfield only calls invalidateIntrinsicContentSize once editing has finished, not during.
Edit: A bunch of "This is not working for me". I think the confusion here is perhaps the triggering event that is tied to the
textFieldDidChange:
handler. The event needs to be UIControlEventEditingChanged. If you're using IB, double check that you're handling the right event.The
UITextField
also cannot be constrained in size. You can lock it into position with constraints, but any width constraint, or set of left+right positioning constraints will prevent it from resizing to its intrinsic content size.I don't know why
UITextField
only updates itsintrinsicContentSize
when it resigns its first responder status. This happens for both iOS 7 and iOS 8.As a temporary solution, I override
intrinsicContentSize
and determine the size usingtypingAttributes
. This accounts forleftView
andrightView
as wellHere I make the it wider to account for the caret
I had a similar requirement with a
UITextView
(had to dynamically increase it's height and some other things).What I did was something similar to this:
Considering
self.contentView
is thesuperview
oftextField
Also, considering the requirements I had, I had to override the
updateConstraints
method of myUITextView
'ssuperview
.Should you choose to opt for that solution (maybe for a more fine tuned approach), you can do:
As mentioned, the override option was used by me because I required a more fine tuned approach.
Additionally, as always you'll need to make sure that you're checking for any edge cases (in terms of sizing values) that you think you might encounter.
Hope this helps!
Cheers!
You can add this code in viewDidLoad to solve the problem.