it-roy-ru.com

Как увеличить ширину текстового поля в соответствии с набранным текстом?

Мне нужно увеличить ширину текстового поля в соответствии с его содержимым. Когда пользователь вводит текст, размер текстового поля должен увеличиваться автоматически. У меня есть одна кнопка закрытия (X) рядом с этим текстовым полем.

Я ограничил текстовое поле и кнопку, чтобы текстовое поле находилось по центру экрана, а кнопка находилась рядом с ним. (Текстовое поле должно быть редактируемым, кнопка должна быть кликабельной)

Размер текстового поля:

 enter image description here

Когда я ввожу в него текст, размер должен автоматически увеличиваться:

 enter image description here

Как мне этого добиться?

21
Mitesh jadav

Я решаю свою проблему: используйте это для текстового поля, а не выходите за пределы экрана.

 func getWidth(text: String) -> CGFloat
{
    let txtField = UITextField(frame: .zero)
    txtField.text = text
    txtField.sizeToFit()
    return txtField.frame.size.width
}

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool
{
    let width = getWidth(textField.text!)
    if UIScreen.mainScreen().bounds.width - 55 > width
    {
        txtWidthOfName.constant = 0.0
        if width > txtWidthOfName.constant
        {
            txtWidthOfName.constant = width
        }
        self.view.layoutIfNeeded()
    }
    return true
}

Цель C Версия

-(CGFloat)getWidth:(NSString *)text{
    UITextField * textField = [[UITextField alloc]initWithFrame:CGRectZero];
    textField.text = text;
    [textField sizeToFit];
    return textField.frame.size.width;
}

-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    if (self.textFieldName.isEditing == YES) {
        CGFloat width = [self getWidth:textField.text];
        if ([UIScreen mainScreen].bounds.size.width - 60 > width) {
            self.txtWidthOfName.constant = 0.0;
            if (width > self.txtWidthOfName.constant) {
                self.txtWidthOfName.constant = width;
            }
            [self.view layoutIfNeeded];
        }
    }
    return YES;
}
11
Mitesh jadav

Вы можете достичь этого с помощью переопределения класса UITextField и вернуть пользовательское значение в intrinsicContentSize. Также вам необходимо подписаться на событие изменения текста и сделать недействительным размер внутреннего содержимого при анимации изменения текста

Вот пример в Swift 3

class Test: UITextField {

    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: nil) { (notification) in
                UIView.animate(withDuration: 0.05, animations: {
                    self.invalidateIntrinsicContentSize()
                })
        }
    }

    deinit {
        NotificationCenter.default.removeObserver(self)
    }

    override var intrinsicContentSize: CGSize {
        if isEditing {
            if let text = text,
                !text.isEmpty {
                // Convert to NSString to use size(attributes:)
                let string = text as NSString
                // Calculate size for current text
                var size = string.size(attributes: typingAttributes)
                // Add margin to calculated size
                size.width += 10
                return size
            } else {
                // You can return some custom size in case of empty string
                return super.intrinsicContentSize
            }
        } else {
            return super.intrinsicContentSize
        }
    }
}
11
Vitaliy Gozhenko

Дерзкий обходной путь для получения ширины для конкретной строки будет 

func getWidth(text: String) -> CGFloat {
    let txtField = UITextField(frame: .zero)
    txtField.text = text
    txtField.sizeToFit()
    return txtField.frame.size.width
}

И чтобы получить ширину,

let width = getWidth(text: "Hello world")
txtField.frame.size.width = width
self.view.layoutIfNeeded() // if you use Auto layout

Если у вас есть ограничение, связанное с шириной txtField, тогда выполните

yourTxtFieldWidthConstraint.constant = width
self.view.layoutIfNeeded() // if you use Auto layout

Правка Мы создаем UITextField с рамкой, состоящей в основном из всех нулей. Когда вы вызываете sizeToFit (), он устанавливает фрейм UITextField таким образом, чтобы отображать весь его контент без буквальных лишних пробелов вокруг него. Нам нужна была только его ширина, поэтому я вернул ширину только что созданного UITextField. ARC позаботится об удалении его из памяти для нас. 

Обновление

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {

        if textField.text != nil {
            let text = textField.text! as NSString
            let finalString = text.replacingCharacters(in: range, with: string)
            textField.frame.size.width = getWidth(text: finalString)
        }

        return true
    }
7
Matt

Все ответы требуют кучу кода, но вы можете сделать все, чтобы построить интерфейс; код не нужен.

Просто вставьте textField в UIStackView и ограничьте, чтобы stackView был меньше или равен его суперпредставлению минус некоторая константа (если вы хотите, вы также можете задать ему минимальную ширину). StackView позаботится о том, чтобы всегда делать textField своим внутренним размером или максимальной шириной stackView (которая когда-либо будет меньше), чтобы при вводе размера размер автоматически изменялся в соответствии с содержимым.

3
Josh Homann

Я думаю, что это лучшее решение, чем ограничение ширины, которое вы должны изменить:

Изменение размера UITextField при наборе текста (с помощью Autolayout)

- (IBAction) textFieldDidChange: (UITextField*) textField
{
    [UIView animateWithDuration:0.1 animations:^{
        [textField invalidateIntrinsicContentSize];
    }];
}

Вы можете опустить анимацию, если хотите ..

EDIT: Вот пример проекта: https://github.com/TomSwift/growingTextField

3
TomSwift

Реализуйте следующий метод UITextFieldDelegate. Используйте подход, предоставленный Мэттом, чтобы получить необходимую ширину textField. В автоматическом макете убедитесь, что для текстового поля установлены ограничения по центру и ширине. Создайте IBOutlet для вашего ограничения ширины в файле кода. Также убедитесь, что вы установили делегат свойство вашего textField

@IBOutlet weak var widthConstraint: NSLayoutConstraint!

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
     let width = getWidth(text : textField.text)
     if width > widthConstraint.constant {
         widthConstraint.constant = width
     }
     self.layoutIfNeeded() 
     return true
}
3
Vishnu gondlekar

Мы можем легко сделать это, установив ограничения UITextField следующим образом:

 enter image description here

// Проверено на Xcode 9.1, Swift 4

Результат:

 enter image description here

2
jpulikkottil

Кажется настолько расстраивающим, что нет прямого пути, как есть «Autoshrink» до «Минимального размера шрифта» для UILabel в самом IB .. "Adjust to Fit" в IB для текстового поля тоже не годится.

Почему Apple заставляет нас писать весь этот стандартный код, когда для текстового поля требуется автоматическое сжатие, если не больше, чем UILabel!

0
iCode