¿Cómo perder margen / relleno en UITextView?

Tengo una UITextView en mi aplicación iOS, que muestra una gran cantidad de texto. Estoy paginando este texto usando el parámetro de margen de desplazamiento de UITextView . Mi problema es que el relleno del UITextView está confundiendo mis cálculos, ya que parece ser diferente según el tamaño de fuente y el tipo de letra que uso.

Por lo tanto, planteo la pregunta: ¿es posible eliminar el relleno que rodea el contenido de UITextView ?

Esperamos escuchar sus respuestas!

Para 2018

Es uno de los errores más tontos en iOS.

UITextViewFixed es generalmente una solución razonable:

 @IBDesignable class UITextViewFixed: UITextView { override func layoutSubviews() { super.layoutSubviews() setup() } func setup() { textContainerInset = UIEdgeInsets.zero textContainer.lineFragmentPadding = 0 } } 

¡No olvide desactivar scrollEnabled en el Inspector!

Esa solución funciona correctamente en el guión gráfico, así como en el tiempo de ejecución.

Eso es todo, has terminado.

En general, eso debería ser todo lo que necesita en la mayoría de los casos .

(Incluso si cambia la altura de la vista de texto sobre la marcha, por ejemplo, a medida que el usuario escribe, esto generalmente hace todo lo que necesita).

Aquí está el UITextView descompuesto de Apple …

captura de pantalla de IB con UITextView

En casi todos los casos, UITextViewFixed es una solución aceptable:

captura de pantalla de IB con UITextViewFixed

(Amarillo añadido para mayor claridad). Tenga en cuenta que, por supuesto, debe

desactive scrollEnabled en el Inspector!

No te olvides de desactivar scrollEnabled! 🙂


Algunos otros problemas

(1) En algunos casos, por ejemplo, a veces cuando se usa el diseño automático con vistas flexibles de la altura de las celdas que cambian de altura sobre la marcha, Apple hace lo más exasperante del mundo: agregan espacio extra en la parte inferior . Tendría que ser una de las cosas más locas y exasperantes de iOS. Aquí hay una “solución rápida” para agregar que a veces ayuda con esa locura.

 ... textContainerInset = UIEdgeInsets.zero textContainer.lineFragmentPadding = 0 // this is not ideal, but you can sometimes use this // to fix the "space at bottom" insanity var b = bounds let h = sizeThatFits(CGSize( width: bounds.size.width, height: CGFloat.greatestFiniteMagnitude) ).height b.size.height = h bounds = b ... 

(2) A veces, para arreglar otra sutil confusión de Apple, debes agregar esto:

 override func setContentOffset(_ contentOffset: CGPoint, animated: Bool) { super.setContentOffset(contentOffset, animated: false) } 

(3) Podría decirse que deberíamos agregar:

 contentInset = UIEdgeInsets.zero 

justo después de .lineFragmentPadding = 0 . Sin embargo … ¡ no funciona en iOS actual! Puede ser necesario agregar eso en futuras versiones del sistema operativo.

El hecho de que UITextView , de todas las cosas, está totalmente roto en iOS es solo una de las cosas más extrañas de toda la informática móvil.

Finalmente, aquí hay un consejo similar para Text Field : https://stackoverflow.com/a/43099816/294884

Para iOS 7.0, he descubierto que el truco de contentInset ya no funciona. Este es el código que utilicé para deshacerme del margen / relleno en iOS 7.

Esto lleva el borde izquierdo del texto al borde izquierdo del contenedor:

 textView.textContainer.lineFragmentPadding = 0 

Esto hace que la parte superior del texto se alinee con la parte superior del contenedor

 textView.textContainerInset = .zero 

Ambas líneas son necesarias para eliminar por completo el margen / relleno.

Esta solución se escribió en 2009 cuando se lanzó IOS 3.0. Ya no se aplica.

Me encontré con exactamente el mismo problema, al final tuve que terminar usando

 nameField.contentInset = UIEdgeInsetsMake(-4,-8,0,0); 

donde nameField es una UITextView . La fuente que estaba usando fue Helvetica 16 punto. Es solo una solución personalizada para el tamaño de campo particular que estaba dibujando. Esto hace que el desplazamiento a la izquierda quede nivelado con el lado izquierdo y el desplazamiento superior donde lo quiero para el cuadro que dibuja.

Además, esto solo parece aplicarse a UITextViews donde está usando la aligmentación predeterminada, es decir.

 nameField.textAlignment = NSTextAlignmentLeft; 

Alinear a la derecha, por ejemplo, y el UIEdgeInsetsMake parece no tener ningún impacto en el borde derecho en absoluto.

Por lo menos, el uso de la propiedad .contentInset le permite colocar sus campos con las posiciones “correctas” y acomodar las desviaciones sin compensar sus UITextViews .

Aprovechando algunas de las buenas respuestas ya dadas, aquí hay una solución puramente basada en Interface Builder que hace uso de los atributos de tiempo de ejecución definidos por el usuario y funciona en iOS 7.0+:

enter image description here

En iOS 5 UIEdgeInsetsMake(-8,-8,-8,-8); parece funcionar bien

Definitivamente evitaría cualquier respuesta que implique valores codificados, ya que los márgenes reales pueden cambiar con la configuración de tamaño de fuente del usuario, etc.

Aquí está la respuesta de @ user1687195, escrita sin modificar el textContainer.lineFragmentPadding (porque los documentos indican que este no es el uso previsto).

Esto funciona muy bien para iOS 7 y versiones posteriores.

 self.textView.textContainerInset = UIEdgeInsetsMake( 0, -self.textView.textContainer.lineFragmentPadding, 0, -self.textView.textContainer.lineFragmentPadding); 

Este es efectivamente el mismo resultado, solo un poco más limpio, ya que no hace un uso indebido de la propiedad lineFragmentPadding.

Solución Storyboard o Interface Builder, utilizando atributos de tiempo de ejecución definidos por el usuario. Actualizar. Se agregaron capturas de pantalla de iOS7.1 e iOS6.1 con contentInset = {{-10, -5}, {0, 0}} enter image description hereenter image description here

Todas estas respuestas abordan la pregunta del título, pero quería proponer algunas soluciones para los problemas presentados en el cuerpo de la pregunta del OP.

Tamaño del contenido de texto

Una forma rápida de calcular el tamaño del texto dentro de UITextView es usar NSLayoutManager :

 UITextView *textView; CGSize textSize = [textView usedRectForTextContainer:textView.textContainer].size; 

Esto proporciona el contenido desplazable total, que puede ser más grande que el marco de UITextView . Encontré esto mucho más preciso que textView.contentSize ya que realmente calcula cuánto espacio ocupa el texto. Por ejemplo, dado un UITextView vacío:

 textView.frame.size = (width=246, height=50) textSize = (width=10, height=16.701999999999998) textView.contentSize = (width=246, height=33) textView.textContainerInset = (top=8, left=0, bottom=8, right=0) 

Altura de la línea

UIFont tiene una propiedad que le permite obtener rápidamente la altura de línea para la fuente dada. Para que pueda encontrar rápidamente el alto de línea del texto en su UITextView con:

 UITextView *textView; CGFloat lineHeight = textView.font.lineHeight; 

Cálculo del tamaño del texto visible

Determinar la cantidad de texto que es realmente visible es importante para manejar un efecto de “búsqueda”. UITextView tiene una propiedad llamada textContainerInset que en realidad es un margen entre el UITextView.frame real y el texto mismo. Para calcular la altura real del marco visible puede realizar los siguientes cálculos:

 UITextView *textView; CGFloat textViewHeight = textView.frame.size.height; UIEdgeInsets textInsets = textView.textContainerInset; CGFloat textHeight = textViewHeight - textInsets.top - textInsets.bottom; 

Determinación del tamaño de paginación

Por último, ahora que tiene el tamaño de texto visible y el contenido, puede determinar rápidamente cuáles deberían ser sus compensaciones restando el textHeight de textHeight del textHeight del textSize :

 // where n is the page number you want CGFloat pageOffsetY = textSize - textHeight * (n - 1); textView.contentOffset = CGPointMake(textView.contentOffset.x, pageOffsetY); // examples CGFloat page1Offset = 0; CGFloat page2Offset = textSize - textHeight CGFloat page3Offset = textSize - textHeight * 2 

Utilicé todos estos métodos, no toqué mis inserciones y pude ir al cursor o al texto que desee.

puede usar la propiedad UITextView de UITextView :

textView.textContainerInset = UIEdgeInsetsMake (10, 10, 10, 10);

(arriba a la izquierda, abajo a la derecha)

Para iOS 10, la siguiente línea funciona para la eliminación de relleno superior e inferior.

 captionTextView.textContainerInset = UIEdgeInsetsMake(0, 0, 0, 0) 

Para swift 4, Xcode 9

Use la siguiente función para cambiar el margen / relleno del texto en UITextView

public func UIEdgeInsetsMake (_ top: CGFloat, _ left: CGFloat, _ bottom: CGFloat, _ right: CGFloat) -> UIEdgeInsets

entonces en este caso es

  self.textView?.textContainerInset = UIEdgeInsetsMake(0, 0, 0, 0) 

Aquí hay una versión actualizada de la respuesta muy útil de Fattie. Agrega 2 líneas muy importantes que me ayudaron a obtener un diseño perfecto trabajando en iOS 10 y 11 (y probablemente también en las más bajas).
re

 @IBDesignable class UITextViewFixed: UITextView { override func layoutSubviews() { super.layoutSubviews() setup() } func setup() { translatesAutoresizingMaskIntoConstraints = true textContainerInset = UIEdgeInsets.zero textContainer.lineFragmentPadding = 0 translatesAutoresizingMaskIntoConstraints = false } } 

Las líneas importantes son las dos declaraciones translatesAutoresizingMaskIntoConstraints = .

¡Esto sorprendentemente elimina todos los márgenes en todas mis circunstancias!

Si bien textView no responde primero, puede ocurrir que exista un margen inferior extraño que no se pudo resolver con el método sizeThatFits que se menciona en la respuesta aceptada.
Al tocar el textView de repente, el extraño margen inferior desapareció y todo parecía como debería, pero solo en cuanto textView obtuvo firstResponder .

Así que leí aquí en SO que habilitar y deshabilitar traduceAutoresizingMaskIntoConstraints ayuda cuando se establece el marco / límites manualmente entre las llamadas.

Afortunadamente, esto no solo funciona con la configuración de fotogtwigs, sino también con las 2 líneas de setup() intercaladas entre las dos llamadas a translatesAutoresizingMaskIntoConstraints .

Esto, por ejemplo, es muy útil cuando se calcula el marco de una vista usando systemLayoutSizeFitting en una UIView . Devuelve el tamaño correcto (¡que antes no lo hacía)!

Como en la respuesta original mencionada:
¡No olvide desactivar scrollEnabled en el Inspector!
Esa solución funciona correctamente en el guión gráfico, así como en el tiempo de ejecución.

Eso es todo, ¡ya terminaste!

Al hacer la solución insertada, todavía tenía relleno en el lado derecho y en el inferior. También la alineación de texto estaba causando problemas. La única forma segura de fuego que encontré fue poner la vista de texto dentro de otra vista que está cortada al límite.

Aquí hay una pequeña extensión fácil que eliminará el margen predeterminado de Apple de cada vista de texto en su aplicación.

Nota: Interface Builder seguirá mostrando el margen antiguo, pero su aplicación funcionará como se esperaba.

 extension UITextView { open override func awakeFromNib() { super.awakeFromNib(); removeMargins(); } /** Removes the Apple textview margins. */ public func removeMargins() { self.contentInset = UIEdgeInsetsMake( 0, -textContainer.lineFragmentPadding, 0, -textContainer.lineFragmentPadding); } } 

Último Swift

self.textView.textContainerInset = .init (arriba: -2, izquierda: 0, abajo: 0, derecha: 0) self.textView.textContainer.lineFragmentPadding = 0

Para mí (iOS 11 y Xcode 9.4.1), lo que funcionó mágicamente fue configurar la propiedad textView.font para el estilo UIFont.preferred(forTextStyle:UIFontTextStyle) y también la primera respuesta mencionada por @Fattie. Pero la respuesta de @Fattie no funcionó hasta que configuré la propiedad textView.font más que UITextView sigue comportándose erráticamente.

He encontrado un enfoque más, obtener vista con texto de las subvistas de UITextView y configurarlo en el método de presentación de una subclase:

 - (void)layoutSubviews { [super layoutSubviews]; const int textViewIndex = 1; UIView *textView = [self.subviews objectAtIndex:textViewIndex]; textView.frame = CGRectMake( kStatusViewContentOffset, 0.0f, self.bounds.size.width - (2.0f * kStatusViewContentOffset), self.bounds.size.height - kStatusViewContentOffset); } 

El desplazamiento de textView también afecta la posición del texto y hace que parezca no centrado verticalmente. Logré centrar el texto en la vista deshabilitando el desplazamiento y estableciendo el recuadro superior en 0:

  textView.scrollEnabled = NO; textView.textContainerInset = UIEdgeInsetsMake(0, textView.textContainerInset.left, textView.textContainerInset.bottom, textView.textContainerInset.right); 

Por algún motivo aún no lo he descubierto, el cursor aún no está centrado antes de que comience a escribir, pero el texto se centra inmediatamente cuando empiezo a escribir.

 [firstNameTextField setContentVerticalAlignment:UIControlContentVerticalAlignmentCenter];