¿Cómo clasifico una UITextView a su contenido?

¿Hay una buena manera de ajustar el tamaño de una UITextView para que se ajuste a su contenido? Digamos, por ejemplo, que tengo una UITextView que contiene una línea de texto:

 "Hello world" 

Luego agrego otra línea de texto:

 "Goodbye world" 

¿Hay una buena manera en Cocoa Touch para obtener el rect que mantendrá todas las líneas en la vista de texto para que pueda ajustar la vista principal en consecuencia?

Como otro ejemplo, observe el campo de notas para eventos en la aplicación Calendario: observe cómo la celda (y el UITextView que contiene) se expande para contener todas las líneas de texto en la cadena de notas.

Esto funciona tanto para iOS 6.1 como para iOS 7:

 - (void)textViewDidChange:(UITextView *)textView { CGFloat fixedWidth = textView.frame.size.width; CGSize newSize = [textView sizeThatFits:CGSizeMake(fixedWidth, MAXFLOAT)]; CGRect newFrame = textView.frame; newFrame.size = CGSizeMake(fmaxf(newSize.width, fixedWidth), newSize.height); textView.frame = newFrame; } 

O en Swift (funciona con Swift 4.1 en iOS 11)

 let fixedWidth = textView.frame.size.width let newSize = textView.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat.greatestFiniteMagnitude)) textView.frame.size = CGSize(width: max(newSize.width, fixedWidth), height: newSize.height) 

Si quieres soporte para iOS 6.1, entonces también deberías:

 textview.scrollEnabled = NO; 

Esto ya no funciona en iOS 7 o superior

En realidad, hay una manera muy fácil de cambiar el tamaño del UITextView a la altura correcta del contenido. Se puede hacer utilizando UITextView .

 CGRect frame = _textView.frame; frame.size.height = _textView.contentSize.height; _textView.frame = frame; 

Una cosa a tener en cuenta es que el contentSize correcto solo está disponible después de que UITextView se haya agregado a la vista con addSubview . Antes de eso, es igual a frame.size

Esto no funcionará si el diseño automático está activado. Con el diseño automático, el enfoque general es usar el método sizeThatFits y actualizar el valor constant en una restricción de altura.

 CGSize sizeThatShouldFitTheContent = [_textView sizeThatFits:_textView.frame.size]; heightConstraint.constant = sizeThatShouldFitTheContent.height; 

heightConstraint es una restricción de diseño que normalmente configura a través de un IBOutlet vinculando la propiedad a la restricción de altura creada en un guión gráfico.


Solo para agregar a esta sorprendente respuesta, 2014, si usted:

 [self.textView sizeToFit]; 

Hay una diferencia en el comportamiento con el iPhone6 ​​+ solamente:

enter image description here

Con el 6+ solamente (no el 5 o el 6) agrega “una línea más en blanco” al UITextView. La “solución RL” corrige esto perfectamente:

 CGRect _f = self.mainPostText.frame; _f.size.height = self.mainPostText.contentSize.height; self.mainPostText.frame = _f; 

Soluciona el problema de la “línea adicional” en 6+.

Para hacer una UITextView tamaño UITextView dentro de una UITableViewCell , encontré que la siguiente combinación funciona en Xcode 6 con iOS 8 SDK:

  • Agregue un UITextView a una UITableViewCell y UITableViewCell a los lados
  • Establezca la propiedad scrollEnabled en NO . Con el desplazamiento habilitado, el marco de UITextView es independiente de su tamaño de contenido, pero con el desplazamiento desactivado, existe una relación entre los dos.
  • Si su tabla usa la altura de fila predeterminada original de 44, entonces calculará automáticamente las alturas de fila, pero si cambió la altura de fila predeterminada a otra cosa, es posible que deba activar manualmente el cálculo automático de alturas de fila en viewDidLoad :

     tableView.estimatedRowHeight = 150; tableView.rowHeight = UITableViewAutomaticDimension; 

Para el tamaño dynamic de solo lectura de UITextView , eso es todo. Si permite que los usuarios editen el texto en su UITextView , también debe:

  • Implemente el método textViewDidChange: del protocolo UITextViewDelegate e tableView a tableView que tableView a pintar cada vez que tableView el texto:

     - (void)textViewDidChange:(UITextView *)textView; { [tableView beginUpdates]; [tableView endUpdates]; } 
  • Y no se olvide de configurar el delegado UITextView en algún lugar, ya sea en Storyboard o en tableView:cellForRowAtIndexPath:

Swift:

 textView.sizeToFit() 

Solo establece

Por código

 textView.scrollEnabled = false 

Por Storyboard

enter image description here

No hay necesidad de hacer nada aparte de esto.

En mi experiencia (limitada),

 - (CGSize)sizeWithFont:(UIFont *)font forWidth:(CGFloat)width lineBreakMode:(UILineBreakMode)lineBreakMode 

no respeta los caracteres de nueva línea, por lo que puede terminar con un CGSize mucho más corto de CGSize que realmente se requiere.

 - (CGSize)sizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size 

parece respetar las nuevas líneas.

Además, el texto no se representa en la parte superior de UITextView . En mi código, configuro la nueva altura del UITextView para que sea 24 píxeles más grande que la altura devuelta por los métodos sizeOfFont .

En iOS6, puede verificar la propiedad contentSize de UITextView justo después de configurar el texto. En iOS7, esto ya no funcionará. Si desea restaurar este comportamiento para iOS7, coloque el siguiente código en una subclase de UITextView.

 - (void)setText:(NSString *)text { [super setText:text]; if (NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_6_1) { CGRect rect = [self.textContainer.layoutManager usedRectForTextContainer:self.textContainer]; UIEdgeInsets inset = self.textContainerInset; self.contentSize = UIEdgeInsetsInsetRect(rect, inset).size; } } 

Voy a publicar la solución correcta en la parte inferior de la página en caso de que alguien sea valiente (o desesperado) para leer hasta este punto.

Aquí está el repository gitHub para aquellos que no quieren leer todo ese texto: resizableTextView

Esto funciona con iOs7 (y creo que funcionará con iOs8) y con autolayout. No necesitas números mágicos, deshabilitar el diseño y cosas así. Solución corta y elegante.

Creo que todo el código relacionado con restricciones debe ir al método updateConstraints . Entonces, hagamos nuestro propio ResizableTextView .

El primer problema que encontramos aquí es que no conoce el tamaño del contenido real antes del método viewDidLoad . Podemos tomar un camino largo y con errores y calcularlo en función del tamaño de la fuente, los saltos de línea, etc. Pero necesitamos una solución sólida, así que haremos:

CGSize contentSize = [self sizeThatFits:CGSizeMake(self.frame.size.width, FLT_MAX)];

Entonces ahora sabemos el contenido real, no importa dónde estemos: antes o después de viewDidLoad . Ahora agregue la restricción de altura en textView (a través del guión gráfico o el código, no importa cómo). Ajustaremos ese valor con nuestro contentSize.height :

 [self.constraints enumerateObjectsUsingBlock:^(NSLayoutConstraint *constraint, NSUInteger idx, BOOL *stop) { if (constraint.firstAttribute == NSLayoutAttributeHeight) { constraint.constant = contentSize.height; *stop = YES; } }]; 

Lo último que debe hacer es decirle a la superclase que updateConstraints .

 [super updateConstraints]; 

Ahora nuestra clase se ve así:

ResizableTextView.m

 - (void) updateConstraints { CGSize contentSize = [self sizeThatFits:CGSizeMake(self.frame.size.width, FLT_MAX)]; [self.constraints enumerateObjectsUsingBlock:^(NSLayoutConstraint *constraint, NSUInteger idx, BOOL *stop) { if (constraint.firstAttribute == NSLayoutAttributeHeight) { constraint.constant = contentSize.height; *stop = YES; } }]; [super updateConstraints]; } 

Bonito y limpio, ¿verdad? ¡Y no tiene que lidiar con ese código en sus controladores !

¡Pero espera! ¡Y SIN ANIMACIÓN!

Puede animar fácilmente los cambios para hacer que textView estire sin problemas. Aquí hay un ejemplo:

  [self.view layoutIfNeeded]; // do your own text change here. self.infoTextView.text = [NSString stringWithFormat:@"%@, %@", self.infoTextView.text, self.infoTextView.text]; [self.infoTextView setNeedsUpdateConstraints]; [self.infoTextView updateConstraintsIfNeeded]; [UIView animateWithDuration:1 delay:0 options:UIViewAnimationOptionLayoutSubviews animations:^{ [self.view layoutIfNeeded]; } completion:nil]; 

¿Lo intentó [textView sizeThatFits:textView.bounds] ?

Editar: sizeThatFits devuelve el tamaño pero en realidad no cambia el tamaño del componente. No estoy seguro de si eso es lo que quieres, o si [textView sizeToFit] es más de lo que estabas buscando. En cualquier caso, no sé si encajará perfectamente en el contenido como lo desea, pero es lo primero que debe intentar.

Otro método es encontrar el tamaño que tomará una cadena en particular utilizando el método NSString :

-(CGSize)sizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size

Esto devuelve el tamaño del rectángulo que se ajusta a la cadena dada con la fuente dada. Pase un tamaño con el ancho deseado y una altura máxima, y ​​luego puede ver la altura devuelta para ajustarse al texto. Hay una versión que le permite especificar el modo de salto de línea también.

A continuación, puede usar el tamaño devuelto para cambiar el tamaño de su vista para que quepa.

Si no tiene el UITextView mano (por ejemplo, está dimensionando las celdas de la vista de tabla), tendrá que calcular el tamaño midiendo la cadena, y luego teniendo en cuenta los 8 puntos de relleno de cada lado de un UITextView . Por ejemplo, si conoce el ancho deseado de su vista de texto y desea calcular la altura correspondiente:

 NSString * string = ...; CGFloat textViewWidth = ...; UIFont * font = ...; CGSize size = CGSizeMake(textViewWidth - 8 - 8, 100000); size.height = [string sizeWithFont:font constrainedToSize:size].height + 8 + 8; 

Aquí, cada 8 representa uno de los cuatro bordes acolchados, y 100000 solo sirve como un tamaño máximo muy grande.

En la práctica, es posible que desee agregar una font.leading adicional que font.leading a la altura; esto agrega una línea en blanco debajo de su texto, que puede verse mejor si hay controles visualmente pesados ​​directamente debajo de la vista de texto.

Las siguientes cosas son suficientes:

  1. Solo recuerde configurar el desplazamiento habilitado en NO para su UITextView :

enter image description here

  1. Establecer correctamente las restricciones de diseño automático.

Incluso puede usar UITableViewAutomaticDimension .

Podemos hacerlo por restricciones.

  1. Establecer restricciones de altura para UITextView. enter image description here

2. Cree IBOutlet para esa restricción de altura.

  @property (weak, nonatomic) IBOutlet NSLayoutConstraint *txtheightconstraints; 

3.no te olvides de configurar delegado para tu vista de texto.

4.

 -(void)textViewDidChange:(UITextView *)textView { CGFloat fixedWidth = textView.frame.size.width; CGSize newSize = [textView sizeThatFits:CGSizeMake(fixedWidth, MAXFLOAT)]; CGRect newFrame = textView.frame; newFrame.size = CGSizeMake(fmaxf(newSize.width, fixedWidth), newSize.height); NSLog(@"this is updating height%@",NSStringFromCGSize(newFrame.size)); [UIView animateWithDuration:0.2 animations:^{ _txtheightconstraints.constant=newFrame.size.height; }]; } 

luego actualiza tu restricción de esta manera 🙂

En combinación con la respuesta de Mike McMaster, es posible que desee hacer algo como:

 [myTextView setDelegate: self]; ... - (void)textViewDidChange:(UITextView *)textView { if (myTextView == textView) { // it changed. Do resizing here. } } 

¡Descubrí una manera de cambiar el tamaño de la altura de un campo de texto de acuerdo con el texto que contiene y también organizar una etiqueta debajo de la altura del campo de texto! Aquí está el código.

 UITextView *_textView = [[UITextView alloc] initWithFrame:CGRectMake(10, 10, 300, 10)]; NSString *str = @"This is a test text view to check the auto increment of height of a text view. This is only a test. The real data is something different."; _textView.text = str; [self.view addSubview:_textView]; CGRect frame = _textView.frame; frame.size.height = _textView.contentSize.height; _textView.frame = frame; UILabel *lbl = [[UILabel alloc] initWithFrame:CGRectMake(10, 5 + frame.origin.y + frame.size.height, 300, 20)]; lbl.text = @"Hello!"; [self.view addSubview:lbl]; 

Chicos que usan el autolayout y su sizetofit no funciona, entonces verifiquen su restricción de ancho una vez. Si te perdiste la restricción de ancho, entonces la altura será precisa.

No es necesario usar ninguna otra API. solo una línea arreglaría todo el problema.

 [_textView sizeToFit]; 

Aquí, solo me preocupaba la altura, mantener el ancho fijo y no tener la restricción de ancho de mi TextView en el guión gráfico.

Y esto fue para mostrar el contenido dynamic de los servicios.

Espero que esto pueda ayudar …

A partir de iOS 8, es posible utilizar las características de diseño automático de una UITableView para cambiar automáticamente el tamaño de una UITextView sin ningún código personalizado. He puesto un proyecto en github que demuestra esto en acción, pero esta es la clave:

  1. El UITextView debe tener el desplazamiento deshabilitado, lo que puede hacer mediante progtwigción o mediante el constructor de interfaz. No cambiará de tamaño si el desplazamiento está habilitado porque el desplazamiento le permite ver el contenido más grande.
  2. En viewDidLoad para UITableViewController, debe establecer un valor para estimatedRowHeight y luego establecer rowHeight en UITableViewAutomaticDimension .
 - (void)viewDidLoad { [super viewDidLoad]; self.tableView.estimatedRowHeight = self.tableView.rowHeight; self.tableView.rowHeight = UITableViewAutomaticDimension; } 
  1. El objective de implementación del proyecto debe ser iOS 8 o superior.

Esto funcionó bien cuando necesité hacer que el texto en una UITextView ajustara a un área específica:

 // El texto ya debe agregarse a la subvista, o contentviewsize será incorrecto.

 - (void) reduceFontToFit: (UITextView *) tv {
     UIFont * font = tv.font;
     double pointSize = font.pointSize;

     while (tv.contentSize.height> tv.frame.size.height && pointSize> 7.0) {
         pointSize - = 1.0;
         UIFont * newFont = [UIFont fontWithName: font.fontName size: pointSize];
         tv.font = newFont;
     }
     if (pointSize! = font.pointSize)
         NSLog (@ "font down to% .1f from% .1f", pointSize, tv.font.pointSize);
 }

aquí está la versión rápida de @jhibberd

  let cell:MsgTableViewCell! = self.tableView.dequeueReusableCellWithIdentifier("MsgTableViewCell", forIndexPath: indexPath) as? MsgTableViewCell cell.msgText.text = self.items[indexPath.row] var fixedWidth:CGFloat = cell.msgText.frame.size.width var size:CGSize = CGSize(width: fixedWidth,height: CGFloat.max) var newSize:CGSize = cell.msgText.sizeThatFits(size) var newFrame:CGRect = cell.msgText.frame; newFrame.size = CGSizeMake(CGFloat(fmaxf(Float(newSize.width), Float(fixedWidth))), newSize.height); cell.msgText.frame = newFrame cell.msgText.frame.size = newSize return cell 

Para iOS 7.0, en lugar de establecer frame.size.height en frame.size.height (que actualmente no hace nada) use [textView sizeToFit] .

Ver esta pregunta

Revisé todas las respuestas y todas mantienen el ancho fijo y ajustan solo la altura. Si desea ajustar también el ancho, puede usar este método muy fácilmente:

así que cuando configuras tu vista de texto, configura el desplazamiento deshabilitado

 textView.isScrollEnabled = false 

y luego en el método de delegado func textViewDidChange(_ textView: UITextView) agregue este código:

 func textViewDidChange(_ textView: UITextView) { let newSize = textView.sizeThatFits(CGSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude)) textView.frame = CGRect(origin: textView.frame.origin, size: newSize) } 

Productos:

enter image description here

enter image description here

deshabilitar el desplazamiento

agregar constantes

y agrega tu texto

 [yourTextView setText:@"your text"]; [yourTextView layoutIfNeeded]; 

si usa UIScrollView , debe agregar esto también;

 [yourScrollView layoutIfNeeded]; -(void)viewDidAppear:(BOOL)animated{ CGRect contentRect = CGRectZero; for (UIView *view in self.yourScrollView.subviews) { contentRect = CGRectUnion(contentRect, view.frame); } self.yourScrollView.contentSize = contentRect.size; } 

Espero que esto ayude:

 - (void)textViewDidChange:(UITextView *)textView { CGSize textSize = textview.contentSize; if (textSize != textView.frame.size) textView.frame.size = textSize; } 

si hay otro que llegue aquí, esta solución funciona para mí, 1 “Ronnie Liew” +4 “usuario63934” (Mi texto llega del servicio web): tenga en cuenta el 1000 (nada puede ser tan grande “en mi caso”)

 UIFont *fontNormal = [UIFont fontWithName:FONTNAME size:FONTSIZE]; NSString *dealDescription = [client objectForKey:@"description"]; //4 CGSize textSize = [dealDescription sizeWithFont:fontNormal constrainedToSize:CGSizeMake(containerUIView.frame.size.width, 1000)]; CGRect dealDescRect = CGRectMake(10, 300, containerUIView.frame.size.width, textSize.height); UITextView *dealDesc = [[[UITextView alloc] initWithFrame:dealDescRect] autorelease]; dealDesc.text = dealDescription; //add the subview to the container [containerUIView addSubview:dealDesc]; //1) after adding the view CGRect frame = dealDesc.frame; frame.size.height = dealDesc.contentSize.height; dealDesc.frame = frame; 

Y eso es … Saludos

La mejor manera que encontré para cambiar el tamaño de la altura de la UITextView de acuerdo con el tamaño del texto.

 CGSize textViewSize = [YOURTEXTVIEW.text sizeWithFont:[UIFont fontWithName:@"SAMPLE_FONT" size:14.0] constrainedToSize:CGSizeMake(YOURTEXTVIEW.frame.size.width, FLT_MAX)]; 

o puede USAR

 CGSize textViewSize = [YOURTEXTVIEW.text sizeWithFont:[UIFont fontWithName:@"SAMPLE_FONT" size:14.0] constrainedToSize:CGSizeMake(YOURTEXTVIEW.frame.size.width, FLT_MAX) lineBreakMode:NSLineBreakByTruncatingTail]; 

Para aquellos que quieren que la vista de texto se mueva hacia arriba y mantenga la posición final

 CGRect frame = textView.frame; frame.size.height = textView.contentSize.height; if(frame.size.height > textView.frame.size.height){ CGFloat diff = frame.size.height - textView.frame.size.height; textView.frame = CGRectMake(0, textView.frame.origin.y - diff, textView.frame.size.width, frame.size.height); } else if(frame.size.height < textView.frame.size.height){ CGFloat diff = textView.frame.size.height - frame.size.height; textView.frame = CGRectMake(0, textView.frame.origin.y + diff, textView.frame.size.width, frame.size.height); } 

El único código que funcionará es el que usa ‘SizeToFit’ como en la respuesta jhibberd anterior, pero en realidad no funcionará a menos que lo llame en ViewDidAppear o lo conecte al evento UITextView text changed.

Basado en la respuesta de Nikita Took, llegué a la siguiente solución en Swift que funciona en iOS 8 con autolayout:

  descriptionTxt.scrollEnabled = false descriptionTxt.text = yourText var contentSize = descriptionTxt.sizeThatFits(CGSizeMake(descriptionTxt.frame.size.width, CGFloat.max)) for c in descriptionTxt.constraints() { if c.isKindOfClass(NSLayoutConstraint) { var constraint = c as! NSLayoutConstraint if constraint.firstAttribute == NSLayoutAttribute.Height { constraint.constant = contentSize.height break } } } 

Respuesta rápida: el siguiente código calcula la altura de su textView.

  let maximumLabelSize = CGSize(width: Double(textView.frame.size.width-100.0), height: DBL_MAX) let options = NSStringDrawingOptions.TruncatesLastVisibleLine | NSStringDrawingOptions.UsesLineFragmentOrigin let attribute = [NSFontAttributeName: textView.font!] let str = NSString(string: message) let labelBounds = str.boundingRectWithSize(maximumLabelSize, options: NSStringDrawingOptions.UsesLineFragmentOrigin, attributes: attribute, context: nil) let myTextHeight = CGFloat(ceilf(Float(labelBounds.height))) 

Ahora puedes establecer la altura de tu textView en myTextHeight

Aquí está la respuesta si necesita cambiar el tamaño de textView y tableViewCell dinámicamente en staticTableView

[ https://stackoverflow.com/a/43137182/5360675%5D%5B1%5D