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;
}
Creo que esta es una solución mejor que tener una restricción de ancho que debe modificar:
Cambiar el tamaño de un UITextField mientras escribe (mediante el uso de Autolayout)
- (IBAction) textFieldDidChange: (UITextField*) textField
{
[UIView animateWithDuration:0.1 animations:^{
[textField invalidateIntrinsicContentSize];
}];
}
Puede omitir la animación si lo desea ..
EDITAR : Aquí hay un proyecto de ejemplo: https://github.com/TomSwift/growingTextField