Actualizado para 2019
Es uno de los errores más tontos en iOS.
La clase dada aquí UITextViewFixed
es generalmente 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 olvide desactivar scrollEnabled en el Inspector!
La solución funciona correctamente en storyboard
La solución funciona correctamente en tiempo de ejecución
Eso es todo, ya terminaste.
En general, eso debería ser todo lo que necesita en la mayoría de los casos .
Incluso si está cambiando la altura de la vista de texto sobre la marcha , UITextViewFixed
generalmente hace todo lo que necesita.
(Un ejemplo común de cambiar la altura sobre la marcha es cambiarlo a medida que el usuario escribe).
Aquí está el UITextView roto de Apple ...
Aqui esta UITextViewFixed
:
Tenga en cuenta que, por supuesto, debe
apague scrollEnabled en el Inspector!
¡No olvides desactivar scrollEnabled! :)
Algunos problemas adicionales
(1) En algunos casos inusuales, por ejemplo, algunos casos de tablas con alturas de celda flexibles y dinámicamente cambiantes, Apple hace algo extraño: agregan espacio adicional en la parte inferior . ¡No realmente! Esta tendría que ser una de las cosas más irritantes en iOS.
Aquí hay una "solución rápida" para agregar a lo anterior que generalmente ayuda con esa locura.
...
textContainerInset = UIEdgeInsets.zero
textContainer.lineFragmentPadding = 0
// this is not ideal, but you can sometimes use this
// to fix 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) A veces, para solucionar otro error sutil 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 .lineFragmentPadding = 0
de UITextViewFixed
.
Sin embargo ... lo creas o no ... ¡ simplemente no funciona en el iOS actual! (Revisado en 2019). Puede ser necesario agregar esa línea en el futuro.
El hecho de que UITextView
se rompa en iOS es una de las cosas más extrañas en toda la informática móvil. ¡Diez años de aniversario de esta pregunta y aún no se ha solucionado!
Finalmente, aquí hay un consejo algo similar para el campo de texto : https://stackoverflow.com/a/43099816/294884
Sugerencia completamente al azar: cómo agregar el "..." al final
A menudo está utilizando un UITextView "como un UILabel". Por lo tanto, desea que trunque el texto usando puntos suspensivos "..."
Si es así, agregue una tercera línea de código en la "configuración":
textContainer.lineBreakMode = .byTruncatingTail
Sugerencia práctica si desea altura cero, cuando no hay texto
A menudo utiliza una vista de texto para mostrar solo texto. Entonces, el usuario en realidad no puede editar nada. Utiliza líneas "0" para indicar que la vista de texto cambiará automáticamente la altura dependiendo de cuántas líneas de texto.
Eso es genial, pero si no hay texto , ¡lamentablemente obtienes la misma altura que si hubiera una línea de texto ! La vista de texto nunca "desaparece".
Si desea que "desaparezca", simplemente agregue 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
}
(Lo hice '1' para que quede claro lo que está sucediendo, '0' está bien).
¿Qué hay de UILabel?
Cuando solo muestra texto, UILabel tiene muchas ventajas sobre UITextView. UILabel no sufre los problemas descritos en esta página de control de calidad. De hecho, la razón por la que todos "nos rendimos" y usamos UITextView es que es difícil trabajar con UILabel. En particular, es ridículamente difícil agregar relleno , correctamente, a UILabel. De hecho, aquí hay una discusión completa sobre cómo "finalmente" agregar correctamente el relleno a UILabel: https://stackoverflow.com/a/58876988/294884 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 difícil con UILabel.