boundingRectWithSize no replicando UITextView

Mi requisito en un proyecto es que el tamaño de fuente de UITextView deba disminuir según el contenido de UITextView . Así que estoy tratando de hacer una estimación del tamaño del text usando boundingRectWithSize .

El problema es que el tamaño de fuente que obtengo es un poco demasiado grande y parte del text se recorta.

Mi funcion:

  -(BOOL)updateTextViewFontSizeForText:(NSString*)text{ float fontSize = self.maximumFontSizeInPoints; self.font = [self.font fontWithSize:fontSize]; CGSize tallerSize ; CGSize stringSize ; do { if (fontSize <= self.minimumFontSizeInPoints) // it just won't fit return NO; fontSize -= 1.0; self.font = [self.font fontWithSize:fontSize]; NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init]; [paragraphStyle setLineBreakMode:NSLineBreakByWordWrapping]; NSDictionary *attributes = @{ NSFontAttributeName: self.font, NSParagraphStyleAttributeName : paragraphStyle }; tallerSize = CGSizeMake(self.frame.size.width,self.frame.size.height-16);// the 16 is given because uitextview adds some offset stringSize = [text boundingRectWithSize:CGSizeMake(self.contentSize.width,CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading attributes:attributes context:nil].size; }while(stringSize.height >= tallerSize.height); if ([self.onTextChangDelegate respondsToSelector:@selector(onTextChangDelegate)]) { [self.onTextChangDelegate onTextChanged:text]; } return YES; } 

Me encontré con el mismo problema al tratar de hacer lo mismo.

El problema es cómo UITextView ejecuta sus saltos de línea en comparación con boundingRectWithSize. Puede leer más detalles aquí: https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/TextLayout/Concepts/CalcTextLayout.html

¡Pero puedes calcular el tamaño exacto! Básicamente hay dos properties de UITextView que debe tener en count para get las estimaciones de tamaño correctas. El primero es textContainer.lineFragmentPadding , el segundo es textContainerInset .

En primer lugar, textContainer.lineFragmentPadding : es posible que hayas notado que el tamaño siempre está desactivado en 10px , esto se debe a que el valor pnetworkingeterminado de los sistemas es 5px . Cuando calcule su tamaño estimado, tendrá que restar este valor del tamaño en el que está comprobando y volver a agregarlo cuando tenga su valor final.

Segundo, textContainerInset . Se trata de un UIEdgeInset que necesitará volver a agregar a su valor calculado final para que coincida con los sistemas.

Este es un código basado en cómo resolví el problema:

 - (CGSize)sizeThatFits:(CGSize)size CGFloat lineFragmentPaddings = self.textContainer.lineFragmentPadding * 2; CGFloat horzPadding = self.textContainerInset.left + self.textContainerInset.right + lineFragmentPaddings; CGFloat vertPadding = self.textContainerInset.top + self.textContainerInset.bottom; size.width -= horzPadding; CGRect boundingRect = [attributedText boundingRectWithSize:size options:NSStringDrawingUsesLineFragmentOrigin context:nil]; size = boundingRect.size; // I found through debugging that adding 0.25 rounded // matches sizeThatFits: identically. Not sure why… size.width += horzPadding + 0.25; size.height += vertPadding + 0.25; size = CGSizeRound(size); return size; } 

Tenga en count que CGSizeRound es solo una function personalizada que escribí que networkingondea el width y la height del CGSize al 0.5 más cercano.

Para la comparación, si crea una segunda UITextView y se cerciora de que textContainer.lineFragmentPadding y textContainerInset son iguales, debería ver los valores casi idénticos al 0.5 más cercano.

Y a su pregunta sobre el cálculo de un pointSize adecuado, este es un pseudo código para eso:

 CGFloat pointSize = 64; CGFloat minPointSize = 32; CGFloat decrementor = 4; CGFloat padding = self.textContainerInset.left + self.textContainerInset.right + lineFragmentPaddings; CGFloat actualWidth = self.maxTextViewSize.width - padding * 2; CGRect boundingRect = CGRectZero; BOOL isValidPointSize = NO; do { if (pointSize < minPointSize) { pointSize = minPointSize; boundingRect.size.height = self.maxTextViewSize.height; isValidPointSize = YES; } else { NSDictionary *defaultAttributes = [self.customTextStorage defaultAttributesForPointSize:pointSize]; NSAttributedString *attrString = [[NSAttributedString alloc] initWithString:string attributes:defaultAttributes]; boundingRect = [attrString boundingRectWithSize:CGSizeMake(actualWidth, 1024) options:NSStringDrawingUsesLineFragmentOrigin context:nil]; // is the height to big? if (boundingRect.size.height > self.maxTextViewSize.height) { // networkinguce the point size for next iteration of loop pointSize -= decrementor; } // passes height test else { isValidPointSize = YES; } } } while (!isValidPointSize); return pointSize; 

Una vez más, lo anterior es un pseudo código basado en mi implementación (no está destinado solo a la caída en reemploop de lo que tienes). ¡Espero que esto ayude!

testing de esta manera

 UITextView *textViewObj;//initialise textview. textViewObj.autoresizesSubviews = NO; textViewObj.autoresizingMask = UIViewAutoresizingNone; 

Esto realmente funciona rápido, obtén la altura original de la vista de text … testing esto, deja que

 size = cellQueue.contentLbl.sizeThatFits(CGSizeMake(cellQueue.contentLbl.frame.size.width,CGFloat(MAXFLOAT))) cellQueue.heightConstraintContentLbl.constant = size.height