Resize a UITextField while typing (by using Autola

2020-01-30 03:43发布

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.

enter image description here

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?

9条回答
做个烂人
2楼-- · 2020-01-30 04:13

For some reason, calling invalidateIntrinsicContentSize wasn't working for me either, but I also ran into issues with the other solutions due to the margins and editing controls.

This solution isn't always needed; if invalidateIntrinsicContentSize works, then all that needs to be done is to add a call to that when the text is changed, as in the other answers. If that isn't working, then here's a solution (adapted from here) I found which also works with a clear control:

class AutoResizingUITextField: UITextField {
    var lastTextBeforeEditing: String?

    override init(frame: CGRect) {
        super.init(frame: frame)
        setupTextChangeNotification()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setupTextChangeNotification()
    }                

    func setupTextChangeNotification() {
        NotificationCenter.default.addObserver(
            forName: Notification.Name.UITextFieldTextDidChange,
            object: self,
            queue: OperationQueue.main) { (notification) in                   
                self.invalidateIntrinsicContentSize()
        }
        NotificationCenter.default.addObserver(
            forName: Notification.Name.UITextFieldTextDidBeginEditing,
            object: self,
            queue: OperationQueue.main) { (notification) in
                self.lastTextBeforeEditing = self.text
        }
    }                

    override var intrinsicContentSize: CGSize {
        var size = super.intrinsicContentSize

        if isEditing, let text = text, let lastTextBeforeEditing = lastTextBeforeEditing {
            let string = text as NSString
            let stringSize = string.size(attributes: typingAttributes)
            let origSize = (lastTextBeforeEditing as NSString).size(attributes: typingAttributes)
            size.width = size.width + (stringSize.width - origSize.width)
        }

        return size
    }

    deinit {
        NotificationCenter.default.removeObserver(self)
    }
}

If invalidateIntrinsicContentSize is working by itself, this will end up double-counting the change so that needs to be checked first.

查看更多
smile是对你的礼貌
3楼-- · 2020-01-30 04:16

Another solution to this is to set leading/trailing constraints to the textField and use isActive to turn them on/off.

When editing start, turn them on, if the text is centered, the effect will be the same (text will seems to be auto resizing as typing). When editing stops, turn constraints off, which will wrap the frame around the text.

查看更多
淡お忘
4楼-- · 2020-01-30 04:17

For me i also added a target to the textfield (UIControlEventEditingChanged)

- (void)textFieldChanged:(UITextField *)textField {
    [textField sizeToFit];
}

if you have a background color, then just update it in delegate method:

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {

    textField.backgroundColor = [UIColor grayColor];
    return YES;
}
查看更多
登录 后发表回答