ios field - ¿Cómo perder margen / relleno en UITextView?




11 fields (17)

Tengo una UITextView en mi aplicación iOS, que muestra una gran cantidad de texto. A continuación, estoy paginando este texto utilizando el parámetro de margen de desplazamiento de la UITextView . Mi problema es que el relleno del UITextView confunde 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 la UITextView ?

Esperamos escuchar sus respuestas!


Answers

Para swift 4, Xcode 9

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

función pública UIEdgeInsetsMake (_ parte superior: CGFloat, _ izquierda: CGFloat, _ parte inferior: CGFloat, _ derecha: CGFloat) -> UIEdgeInsets

así que en este caso es

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

Para 2018

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

La clase UITextViewFixed es generalmente una solución razonable.

Aquí está la clase:

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

¡No olvide apagar 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

Eso es todo, ya está hecho.

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, esto generalmente hace todo lo que necesita.

(Un ejemplo común de cambio de altura sobre la marcha, es cambiarlo según el tipo de usuario).

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

Aquí está UITextViewFixed :

Tenga en cuenta que por supuesto usted debe

apagar scrollEnabled en el inspector!

No te olvides de apagar scrollEnabled! :)

Algunos problemas adicionales

(1) En algunos casos inusuales, por ejemplo, algunos casos de vistas de tabla de altura de celda flexible con altura que cambia dinámicamente, Apple hace la cosa más molesta del mundo: agrega espacio adicional en la parte inferior . ¡No realmente! Esta tendría que ser una de las cosas más molestas en iOS.

Aquí hay una "solución rápida" para agregar que a menudo 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 otro problema 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 de .lineFragmentPadding = 0 en UITextViewFixed . Sin embargo ... simplemente no funciona en iOS actual! Puede ser necesario agregar eso en el futuro.

El hecho de que UITextView esté totalmente roto en iOS es una de las cosas más extrañas de toda la computación móvil.

Finalmente, aquí hay una sugerencia algo similar para el campo de texto: https://.com/a/43099816/294884


A partir de algunas de las buenas respuestas que ya se dieron, aquí se encuentra una solución basada exclusivamente en Interface Builder que utiliza los atributos de tiempo de ejecución definidos por el usuario y funciona en iOS 7.0+:


Ú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 la configuración de la propiedad textView.font para el estilo UIFont.preferred(forTextStyle:UIFontTextStyle) y también la primera respuesta como lo menciona @Fattie. Pero la respuesta de @Fattie no funcionó hasta que configuré la propiedad textView.font, de lo contrario, UITextView sigue comportándose de forma errática.


Para iOS 7.0, he encontrado que el truco contentInset ya no funciona. Este es el código que usé 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.


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 para iOS 10 y 11 (y probablemente también para 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 = <true/false> !

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

Si bien textView no es el primer respondedor, puede suceder que haya un margen inferior extraño que no se pueda 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 que debía, pero solo en cuanto el textView tiene el primer firstResponder .

Así que leí aquí en SO que habilitar y deshabilitar translatesAutoresizingMaskIntoConstraints ayuda al configurar el marco / límites manualmente entre las llamadas.

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

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

Como en la respuesta original mencionada:
¡No olvide apagar 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 está hecho!


En iOS 5 UIEdgeInsetsMake(-8,-8,-8,-8); Parece funcionar muy bien.


Puedes usar la propiedad UITextView de UITextView :

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

(arriba a la izquierda, abajo a la derecha)


He encontrado un enfoque más, obteniendo la vista con el texto de las subvistas de UITextView y configurándolo en el método layoutSubview 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);
}

Storyboard o solución Interface Builder, utilizando atributos de tiempo de ejecución definidos por el usuario. Actualizar. Se agregaron capturas de pantalla de iOS7.1 y iOS6.1 con contentInset = {{-10, -5}, {0, 0}}


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

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

Por alguna razón aún no lo he descubierto, el cursor aún no está centrado antes de que comience la escritura, pero el texto se centra inmediatamente cuando comienzo a escribir.


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 anterior, 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);
   }
}

Definitivamente evitaría cualquier respuesta que involucre 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 la docs indica 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 mal uso de la propiedad lineFragmentPadding.


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 del 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 total desplazable, que puede ser más grande que el UITextView la UITextView . Descubrí que esto es mucho más preciso que textView.contentSize ya que en realidad calcula la cantidad de espacio que 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 la altura 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 "paginación". UITextView tiene una propiedad llamada textContainerInset que en realidad es un margen entre el actual UITextView.frame y el texto en sí. 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;

Determinar el tamaño de paginación

Finalmente, ahora que tiene el tamaño del texto visible y el contenido, puede determinar rápidamente cuáles deberían ser sus compensaciones restando el 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

Usando todos estos métodos, no toqué mis recuadros y pude ir al caret o a cualquier parte del texto que quiero.


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

Me encontré con el mismo problema, 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 16 puntos. Es solo una solución personalizada para el tamaño de campo particular que estaba dibujando. Esto hace que el offset izquierdo quede al ras con el lado izquierdo, y el offset superior donde lo quiero para el cuadro en el que se dibuja.

Además, parece que esto solo se aplica a UITextViews en las que está usando la alineació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.

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


si alguna otra persona llega, esta solución funciona para mí, 1 "Ronnie Liew" +4 "user63934" (Mi texto llega del servicio web): note el 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 ... Saludos.





ios iphone cocoa-touch uikit uitextview