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.

¿Fue útil?

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:

enter image description here

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 un UITableViewCell y limitarlo a los lados
  • Selecciona el UITextView's scrollEnabled propiedad a NO.Con el desplazamiento habilitado, el marco de la UITextView 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 UITextViews, eso es todo.Si permites que los usuarios editen el texto en tu UITextView, también necesitas:

  • Implementar el textViewDidChange: método de la UITextViewDelegate protocolo y decirle al tableView 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 en Storyboard o en tableView:cellForRowAtIndexPath:

Rápido:

textView.sizeToFit()

Solución de trabajo muy sencilla que utiliza código y guión gráfico.

Por código

textView.scrollEnabled = false

Por guión gráfico

Desmarque el Habilitar desplazamiento

enter image description here

No es necesario hacer nada aparte de esto.

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.

Lo siguiente es suficiente:

  1. Sólo recuerda configurar desplazamiento habilitado a NO para tu UITextView:

enter image description here

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

Incluso puedes usar UITableViewAutomaticDimension.

Podemos hacerlo por restricciones.

  1. Establezca 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 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:

  1. 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.
  2. En viewDidLoad para UITableViewController, debe establecer un valor para estimadaRowHeight y luego establecer el rowHeight a UITableViewAutomaticDimension.

- (void)viewDidLoad {
    [super viewDidLoad];
    self.tableView.estimatedRowHeight = self.tableView.rowHeight;
    self.tableView.rowHeight = UITableViewAutomaticDimension;
}
  1. 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:

enter image description here

enter image description here

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

[https://stackoverflow.com/a/43137182/5360675][1]

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top