Cómo perder margen/relleno en UITextView

Resuelto sniurkst asked hace 54 años • 24 respuestas

Tengo UITextViewen mi aplicación iOS, que muestra una gran cantidad de texto.

Luego estoy paginando este texto usando el parámetro de margen de desplazamiento del archivo UITextView.

Mi problema es que el relleno UITextViewconfunde mis cálculos, ya que parece ser diferente según el tamaño de fuente y el tipo de letra que uso.

¿Es posible eliminar el relleno que rodea el contenido del UITextView?

sniurkst avatar Jan 01 '70 08:01 sniurkst
Aceptado

Para iOS 7.0, descubrí que el truco 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 completamente el margen/relleno.

user1687195 avatar Sep 24 '2013 17:09 user1687195

Actualizado para 2023

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

La clase proporcionada aquí UITextViewFixedse usa ampliamente y suele ser la solución más razonable en general .

Aquí está la clase:

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

¡No olvides desactivar scrollEnabled en el Inspector!

  1. La solución funciona correctamente en el guión gráfico.

  2. La solución funciona correctamente en tiempo de ejecución.

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

Incluso si cambia la altura de la vista de texto sobre la marcha , UITextViewFixednormalmente hace todo lo que necesita.

(Un ejemplo común de cambiar la altura sobre la marcha es cambiarla a medida que el usuario escribe).

Aquí está el UITextView roto de Apple...

Captura de pantalla de Interface Builder con UITextView

Aquí está UITextViewFixed:

Captura de pantalla de Interface Builder con UITextViewFixed

Tenga en cuenta que, por supuesto, debe...

... ¡desactive scrollEnabled en el Inspector!

(Activar scrollEnabled significa "hacer que esta vista se expanda tanto como sea posible verticalmente expandiendo el margen inferior tanto como sea posible").


Algunas cuestiones adicionales

(1) En casos muy inusuales, cuando las alturas cambian dinámicamente, Apple hace algo extraño: agrega espacio adicional en la parte inferior .

¡No realmente! Esta tendría que ser una de las cosas más exasperantes en iOS.

Si encuentra el problema, aquí tiene una "solución rápida" que normalmente ayuda:

...
        textContainerInset = UIEdgeInsets.zero
        textContainer.lineFragmentPadding = 0

        // this is not ideal, but sometimes this "quick fix"
        // will solve the "extra space at the bottom" insanity:
        var b = bounds
        let h = sizeThatFits(CGSize(
           width: bounds.size.width,
           height: CGFloat.greatestFiniteMagnitude)
       ).height
       b.size.height = h
       bounds = b
 ...

(2) En casos excepcionales, para solucionar otro error sutil de Apple, debes agregar:

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

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

contentInset = UIEdgeInsets.zero

justo después .lineFragmentPadding = 0en UITextViewFixed.

Sin embargo, lo creas o no, ¡eso simplemente no funciona en el iOS actual! (Comprobado en 2023). Es posible que sea necesario agregar esa línea en el futuro.

El hecho de que UITextViewiOS esté roto es una de las cosas más extrañas en toda la informática móvil. ¡Diez años de esta pregunta y aún no se ha solucionado!

Finalmente, aquí hay un consejo algo similar para el campo de texto : establezca la longitud máxima de caracteres de un UITextField en Swift

Consejo completamente aleatorio: cómo agregar el "..." al final

A menudo estás utilizando un UITextView "como un UILabel". Entonces quieres que trunque el texto usando puntos suspensivos, "..."

Si es así, agregue:

 textContainer.lineBreakMode = .byTruncatingTail

Consejo útil si desea una altura cero cuando no hay ningún texto

A menudo se utiliza una vista de texto para mostrar solo texto. Entonces, usa las líneas "0" para significar que la vista de texto cambiará automáticamente la altura dependiendo de cuántas líneas de texto.

Genial. Pero si no hay ningún texto , desafortunadamente obtendrás la misma altura que si hubiera una línea de texto . La vista de texto nunca "desaparece".

Ingrese la descripción de la imagen aquí

Si quieres que "desaparezca", simplemente agrega esto

override var intrinsicContentSize: CGSize {
    var i = super.intrinsicContentSize
    print("for \(text) size will be \(i)")
    if text == "" { i.height = 1.0 }
    print("   but we changed it to \(i)")
    return i
}

Ingrese la descripción de la imagen aquí

(Hice una altura de '1', para que quede claro lo que sucede en esa demostración; '0' está bien).

¿Qué pasa con UILabel?

Cuando solo muestra texto, UILabel tiene muchas ventajas sobre UITextView. UILabel no sufre los problemas descritos en esta página de preguntas y respuestas.

De hecho, la razón por la que todos normalmente "nos rendimos" y simplemente usamos UITextView es que es difícil trabajar con UILabel. En particular, es ridículamente difícil simplemente agregar padding , correctamente, a UILabel.

De hecho, aquí hay una discusión completa sobre cómo "finalmente" agregar correctamente relleno a UILabel: Agregar espacio/relleno a UILabel . En algunos casos, si está haciendo un diseño difícil con celdas de altura dinámica, a veces es mejor hacerlo de la manera más difícil con UILabel.

Fattie avatar Feb 19 '2017 22:02 Fattie

Esta solución alternativa se escribió en 2009, cuando se lanzó iOS 3.0. Ya no se aplica.

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

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

donde nameField es un UITextView. La fuente que estaba usando era Helvetica de 16 puntos. Es sólo una solución personalizada para el tamaño de campo particular que estaba dibujando. Esto hace que el desplazamiento izquierdo quede alineado con el lado izquierdo y el desplazamiento superior donde lo quiero para el cuadro en el que está dibujado.

Además, esto sólo parece aplicarse UITextViewscuando se utiliza la alineación predeterminada, es decir,

nameField.textAlignment = NSTextAlignmentLeft;

Alinee a la derecha, por ejemplo, y UIEdgeInsetsMakeparece no tener ningún impacto en el borde derecho.

Como mínimo, usar la propiedad .contentInset le permite colocar sus campos con las posiciones "correctas" y acomodar las desviaciones sin compensar su UITextViews.

Michael avatar Jul 26 '2009 18:07 Michael

A partir de algunas de las buenas respuestas ya dadas, aquí hay una solución puramente basada en Storyboard/Interfaz Builder que funciona en iOS 7.0+

Configure los atributos de tiempo de ejecución definidos por el usuario de UITextView para las siguientes claves:

textContainer.lineFragmentPadding
textContainerInset

Generador de interfaces

dvs avatar Feb 04 '2015 00:02 dvs