ios swift autolayout uitextfield

ios - ¿Cómo aumentar el ancho del campo de texto de acuerdo con el texto escrito?



swift autolayout (8)

Necesito aumentar el ancho de un campo de texto de acuerdo a su contenido. Cuando el usuario ingresa texto, el tamaño del campo de texto debe aumentar automáticamente. Tengo un botón Cerrar (X) al lado de este campo de texto.

He restringido el campo y el botón de texto para que el campo de texto se centre en la pantalla y el botón esté junto a él. (El campo de texto debe ser editable, se debe poder hacer clic en el botón)

El tamaño del campo de texto es este:

Cuando ingreso texto, el tamaño debería aumentar automáticamente:

¿Cómo puedo conseguir esto?


Implementar el siguiente método de UITextFieldDelegate . Utilice el enfoque proporcionado por Matt para obtener el ancho requerido de textField. En el diseño automático, asegúrese de tener restricciones de centro y ancho establecidas para el campo de texto. Crea IBOutlet para tu restricción de ancho en el archivo de código. También asegúrese de establecer la propiedad de delegado de su campo de texto

@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 }


Una solución descarada para obtener ancho para una cadena en particular sería

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

Y para obtener el ancho,

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

Si tiene una restricción vinculada al ancho de txtField, haga

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

Editar Estamos creando un UITextField con un marco de básicamente todos los ceros. Cuando llame a sizeToFit (), establecerá el marco de UITextField de una manera que mostrará todo su contenido literalmente sin espacios adicionales alrededor de él. Solo queríamos su ancho, así que devolví el ancho del UITextField recién creado. ARC se encargará de eliminarlo de la memoria para nosotros.

Actualizar

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 }


Puede lograrlo anulando la clase UITextField y devolviendo el valor personalizado en intrinsicContentSize . También necesita suscribirse al evento de cambio de texto e invalidar el tamaño del contenido intrínseco en el cambio de texto animado

Aquí hay un ejemplo en 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 } } }


Parece tan frustrante que no hay una manera directa como hay "Autoshrink" para "Tamaño mínimo de fuente" para UILabel en IB. El "Ajuste para ajustar" en IB para un campo de texto tampoco es bueno.

¿Por qué Apple nos obliga a escribir todo este código repetitivo, cuando un campo de texto necesita Autoshrink tanto o más que el UILabel!


Todas las respuestas requieren un montón de código, pero puedes hacer todo el constructor de interfaz; no se necesita código

Simplemente incruste textField en UIStackView y obligue a stackView a ser menor o igual que su superview menos alguna constante (si lo desea, también puede darle un ancho mínimo). El stackView se ocupará de hacer que el campo de texto sea siempre su tamaño intrínseco, o el ancho máximo de stackView (que sea menor), de modo que al escribir el tamaño, el tamaño cambiará automáticamente para ajustarse al contenido.


Resuelvo mi problema: use esto para el campo de texto no fuera de la pantalla.

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 }

Versión Objetivo 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; }



Podemos hacerlo fácilmente estableciendo restricciones de UITextField como esta:

// Probado en Xcode 9.1, Swift 4

Salida: