¿Cómo puedo dimensionar un UITextView según su contenido?
-
09-06-2019 - |
Pregunta
¿Existe una buena manera de ajustar el tamaño de un UITextView
para ajustarse a su contenido?Digamos por ejemplo que tengo un UITextView
que contiene una línea de texto:
"Hello world"
Luego agrego otra línea de texto:
"Goodbye world"
¿Existe una buena manera en Cocoa Touch de obtener el rect
¿Eso contendrá todas las líneas en la vista de texto para que pueda ajustar la vista principal en consecuencia?
Como otro ejemplo, mire 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.
Solución
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 desea soporte para iOS 6.1, también debe:
textview.scrollEnabled = NO;
Otros consejos
Esto ya no funciona en iOS 7 o superior
En realidad, existe una forma muy sencilla de cambiar el tamaño del UITextView
a su altura correcta del contenido.Se puede hacer usando el UITextView
contentSize
.
CGRect frame = _textView.frame;
frame.size.height = _textView.contentSize.height;
_textView.frame = frame;
Una cosa a tener en cuenta es que la correcta contentSize
solo esta disponible después el UITextView
se ha 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 utilizar el sizeThatFits
método y actualizar el constant
valor 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 se 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:
[self.textView sizeToFit];
hay una diferencia de comportamiento con el iPhone6+ solo:
Solo con el 6+ (no con el 5 o el 6) agrega "una línea en blanco más" a UITextView.La "solución RL" soluciona 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 un dimensionamiento dinámicamente UITextView
dentro de una UITableViewCell
, encontré que la siguiente combinación funciona en Xcode 6 con el SDK de iOS 8:
- Agrega un
UITextView
a unUITableViewCell
y limitarlo a los lados - Selecciona el
UITextView
'sscrollEnabled
propiedad aNO
.Con el desplazamiento habilitado, el marco de laUITextView
es independiente del tamaño de su contenido, pero con el desplazamiento deshabilitado, existe una relación entre los dos. Si su tabla utiliza la altura de fila predeterminada original de 44, 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 dimensionamiento dinámico de solo lectura UITextView
s, eso es todo.Si permites que los usuarios editen el texto en tu UITextView
, también necesitas:
Implementar el
textViewDidChange:
método de laUITextViewDelegate
protocolo y decirle altableView
para volver a pintarse cada vez que se edita el texto:- (void)textViewDidChange:(UITextView *)textView; { [tableView beginUpdates]; [tableView endUpdates]; }
Y no olvide configurar el
UITextView
delegar en algún lugar, ya sea enStoryboard
o entableView:cellForRowAtIndexPath:
Rápido:
textView.sizeToFit()
En mi (limitada) experiencia,
- (CGSize)sizeWithFont:(UIFont *)font forWidth:(CGFloat)width lineBreakMode:(UILineBreakMode)lineBreakMode
no respeta los caracteres de nueva línea, por lo que puedes terminar con caracteres mucho más cortos. CGSize
de lo que realmente se requiere.
- (CGSize)sizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size
Parece respetar las nuevas líneas.
Además, el texto en realidad no se representa en la parte superior de la UITextView
.En mi código, configuro la nueva altura del UITextView
ser 24 píxeles más grande que la altura devuelta por el sizeOfFont
métodos.
En iOS6, puedes comprobar el contentSize
propiedad 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;
}
}
Publicaré la solución correcta al final de la página en caso de que alguien sea valiente (o esté lo suficientemente desesperado) como para leer hasta este punto.
Aquí está el repositorio de gitHub para aquellos que no quieren leer todo ese texto: vista de texto redimensionable
Esto funciona con iOs7 (y creo que funcionará con iOs8) y con diseño automático.No necesitas números mágicos, desactivar el diseño y cosas así. Solución breve y elegante.
Creo que todo el código relacionado con restricciones debería ir a updateConstraints
método.Entonces, hagamos el nuestro ResizableTextView
.
El primer problema que encontramos aquí es que no conocemos el tamaño real del contenido antes. viewDidLoad
método.Podemos tomar un camino largo y lleno de errores y calcularlo en función del tamaño de fuente, saltos de línea, etc.Pero necesitamos una solución sólida, por eso haremos:
CGSize contentSize = [self sizeThatFits:CGSizeMake(self.frame.size.width, FLT_MAX)];
Ahora conocemos el tamaño del contenido real sin importar dónde estemos:antes o después viewDidLoad
.Ahora agregue una restricción de altura en textView (a través de un guión gráfico o código, sin importar 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];
}
Bonita y limpia, ¿verdad?Y no tienes que lidiar con ese código en tu controladores!
¡Pero espera! ¡SIN ANIMACIÓN!
Puedes animar fácilmente los cambios para realizar textView
estirar suavemente.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];
Has probado [textView sizeThatFits:textView.bounds]
?
Editar:sizeThatFits devuelve el tamaño pero en realidad no cambia el tamaño del componente.No estoy seguro si eso es lo que quieres o si [textView sizeToFit]
Es más lo que estabas buscando.En cualquier caso, no sé si se ajustará perfectamente al contenido que quieres, pero es lo primero que debes probar.
Otro método es encontrar el tamaño que ocupará una cuerda en particular usando el NSString
método:
-(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 podrá ver la altura devuelta para ajustarse al texto.Existe una versión que también le permite especificar el modo de salto de línea.
Luego puede usar el tamaño devuelto para cambiar el tamaño de su vista para que se ajuste.
Si no tienes el UITextView
útil (por ejemplo, si está dimensionando celdas de una vista de tabla), tendrá que calcular el tamaño midiendo la cadena y luego teniendo en cuenta los 8 puntos de relleno en cada lado de una 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 simplemente sirve como un tamaño máximo muy grande.
En la práctica, es posible que desees agregar un extra font.leading
a la altura;esto agrega una línea en blanco debajo del texto, que puede verse mejor si hay controles visualmente pesados directamente debajo de la vista de texto.
Podemos hacerlo por restricciones.
2.Cree IBOutlet para esa restricción de altura.
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *txtheightconstraints;
3. No olvides configurar el 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 actualice su restricción de esta manera :)
Combinado 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 según 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 diseño automático y su tamaño para ajustar no funciona, verifiquen su restricción de ancho una vez.Si no cumplió con la restricción de ancho, entonces la altura será precisa.
No es necesario utilizar ninguna otra API.solo una línea solucionaría todo el problema.
[_textView sizeToFit];
Aquí, solo me preocupaba la altura, mantenía el ancho fijo y había omitido la restricción de ancho de mi TextView en el guión gráfico.
Y esto fue para mostrar el contenido dinámico de los servicios.
Espero que esto pueda ayudar.
A partir de iOS 8, es posible utilizar las funciones de diseño automático de UITableView para cambiar automáticamente el tamaño de UITextView sin ningún código personalizado.He puesto un proyecto en github eso lo demuestra en acción, pero aquí está la clave:
- UITextView debe tener el desplazamiento deshabilitado, lo que puede hacer mediante programación o mediante el generador de interfaces.No cambiará de tamaño si el desplazamiento está habilitado porque el desplazamiento le permite ver el contenido más grande.
- En viewDidLoad para UITableViewController, debe establecer un valor para estimadaRowHeight y luego establecer el
rowHeight
aUITableViewAutomaticDimension
.
- (void)viewDidLoad {
[super viewDidLoad];
self.tableView.estimatedRowHeight = self.tableView.rowHeight;
self.tableView.rowHeight = UITableViewAutomaticDimension;
}
- El objetivo de implementación del proyecto debe ser iOS 8 o superior.
Esto funcionó muy bien cuando necesitaba hacer texto en un UITextView
adaptarse a un área específica:
// The text must already be added to the subview, or contentviewsize will be wrong. - (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
Revisé todas las respuestas y todas mantienen el ancho fijo y ajustan solo la altura.Si desea ajustar también el ancho, puede utilizar este método muy fácilmente:
entonces, cuando configure su vista de texto, configure el desplazamiento deshabilitado
textView.isScrollEnabled = false
y luego en el método delegado func textViewDidChange(_ textView: UITextView)
agrega 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)
}
Salidas:
desactivar el desplazamiento
agregar constantes
y agrega tu texto
[yourTextView setText:@"your text"];
[yourTextView layoutIfNeeded];
si utiliza UIScrollView
deberías 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;
}
Para iOS 7.0, en lugar de configurar el frame.size.height
hacia contentSize.height
(que actualmente no hace nada) usa [textView sizeToFit]
.
Ver esta pregunta.
Espero que esto ayude:
- (void)textViewDidChange:(UITextView *)textView {
CGSize textSize = textview.contentSize;
if (textSize != textView.frame.size)
textView.frame.size = textSize;
}
Si llega algún otro, esta solución me funciona, 1"Ronnie Liew"+4"user63934" (Mi texto llega del servicio web):tenga en cuenta los 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...Salud
La mejor manera que descubrí es cambiar el tamaño de la altura de 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 puedes 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 desean que la vista de texto realmente suba 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 anterior de jhibberd, pero en realidad no se activará a menos que lo llames. VerApareció o conéctelo al evento de cambio de texto UITextView.
Según la respuesta de Nikita Took, llegué a la siguiente solución en Swift que funciona en iOS 8 con diseño automático:
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 vista de texto en myTextHeight
Aquí está la respuesta si necesitas cambiar el tamaño. textView
y tableViewCell
dinámicamente en staticTableView