2012-06-28 10 views
17

Mi aplicación consiste en NSScrollView, cuya vista del documento contiene una cantidad de NSTextViews apilados verticalmente, cada uno de los cuales cambia de tamaño en la dirección vertical a medida que se agrega el texto.Uso del ajuste automático con NSTextViews en expansión

Actualmente, todo esto se gestiona en código. El NSTextViews cambia el tamaño automáticamente, pero observo su cambio de tamaño con NSViewFrameDidChangeNotification, recalca todos sus orígenes para que no se superpongan y cambia el tamaño de su supervista (la vista de documento de la vista desplazada) para que quepan y se puedan desplazar.

¡Parece que sería el candidato perfecto para el diseño automático! Establecí NSLayoutConstraints entre la primera vista de texto y su contenedor, la última vista de texto y su contenedor, y cada vista de texto entre sí. Luego, si crece cualquier vista de texto, automáticamente "empuja hacia abajo" los orígenes de las vistas de texto debajo de ella para satisfacer los inconvenientes, en última instancia, aumentando el tamaño de la vista del documento, ¡y todos están felices!

Excepto que parece que no hay forma de hacer que un NSTextView crezca automáticamente a medida que se agrega texto en un diseño basado en restricciones. Utilizando exactamente el mismo NSTextView que se expandió automáticamente a medida que se ingresaba texto, si no especifico una restricción para su altura, se convierte en 0 y no se muestra. Si especifico una restricción, incluso una desigualdad como> = 20, permanece estancada en ese tamaño y no crece a medida que se agrega el texto.

Sospecho que esto tiene que ver con la implementación de NSTextView de -intrinsicContentSize, que de forma predeterminada devuelve (NSViewNoInstrinsicMetric, NSViewNoInstrinsicMetric).

Así que mis preguntas: si subclases NSTextView para devolver un intrinsicContentSize más significativo según el diseño de mi texto, ¿funcionaría mi autolayout como esperaba?

¿Alguna sugerencia sobre la implementación de intrinsicContentSize para un NSTextView de tamaño vertical?

+0

¿Es posible añadir un poco de gráfica/pantalla/wireframe para facilitar la comprensión de la configuración por favor? ¿Intentó calcular la altura del texto y devolverlo en 'intrinsicContentSize'? – JJD

Respuesta

10

Tuve un problema similar con un NSTextField, y resultó que era debido a la vista que quería abrazar fuertemente su contenido de texto a lo largo de la orientación vertical. Entonces, si configuras la prioridad de abrazos de contenido en algo más bajo que las prioridades de tus otras restricciones, puede funcionar. Ej .:

[textView setContentHuggingPriority:NSLayoutPriorityFittingSizeCompression-1.0 forOrientation:NSLayoutConstraintOrientationVertical]; 
+0

Estoy tan contento de haber encontrado esto. Descubrí que tenía que hacer esto para 'NSTextField's alineados verticalmente en un 'NSSplitView', ¡pero solo cuando podían seleccionarse y no editarse! Tan extraño que el comportamiento de edición afecta las limitaciones, pero ahí lo tienes. Cambié la prioridad horizontal de abrazar contenido para cada uno de ellos de 250 a 249 y el problema desapareció. – theory

+0

En Swift 4 esto parece ser 'setContentHuggingPriority (NSLayoutConstraint.Priority.fittingSizeCompression, para: NSLayoutConstraint.Orientation.vertical)' no estoy seguro de cuál es el significado de -1 pero parece que funciona sin él. Gracias, Marc! –

18

estoy trabajando en una configuración muy similar - una pila vertical de las vistas que contienen las vistas de texto que se expanden para adaptarse a sus contenidos de texto y utilizar el diseño automático.

Hasta ahora han tenido que subclase NSTextView, que es que no se siente limpio, pero funciona magníficamente en la práctica:

- (NSSize) intrinsicContentSize { 
    NSTextContainer* textContainer = [self textContainer]; 
    NSLayoutManager* layoutManager = [self layoutManager]; 
    [layoutManager ensureLayoutForTextContainer: textContainer]; 
    return [layoutManager usedRectForTextContainer: textContainer].size; 
} 

- (void) didChangeText { 
    [super didChangeText]; 
    [self invalidateIntrinsicContentSize]; 
} 

El tamaño inicial de la vista de texto cuando se añade con addSubview es, curiosamente, no el tamaño intrínseco; Todavía no he descubierto cómo emitir la primera invalidación (conectar viewDidMoveToSuperview no ayuda), pero estoy seguro de que finalmente lo resolveré.

+2

¡Muy útil! ¡Gracias por compartir tus hallazgos! – jemmons

+1

Nota: actualmente estoy tratando de obtener el tamaño para animar sin problemas, y experimentar si puedo usar autolayouts para controlar la altura en su lugar (o complementar el tamaño intrínseco). Resulta que puede modificar una restricción dándole una nueva altura llamando a '[constraint setConstant: newHeight]', donde 'constraint' es una restricción única que proporciona la configuración de altura. Funciona en este momento, pero entra en conflicto con el cambio de tamaño automático de 'NSTextContainer', lo que produce un parpadeo. –

3

Aquí es cómo hacer una NSTextView expandir el uso de Auto Layout, en Swift 3 enter image description here

  • Solía ​​Anchors de Diseño automático
  • Uso textDidChange de NSTextDelegate.NSTextViewDelegate se ajusta a NSTextDelegate
  • La idea es que textView tiene edges limitaciones, lo que significa que cada vez que sus intrinsicContentSize cambios, que ampliará su padre, que es scrollView

    import Cocoa 
    import Anchors 
    
    class TextView: NSTextView { 
        override var intrinsicContentSize: NSSize { 
        guard let manager = textContainer?.layoutManager else { 
         return .zero 
        } 
    
        manager.ensureLayout(for: textContainer!) 
    
        return manager.usedRect(for: textContainer!).size 
        } 
    } 
    
    class ViewController: NSViewController, NSTextViewDelegate { 
    
        @IBOutlet var textView: NSTextView! 
        @IBOutlet weak var scrollView: NSScrollView! 
        override func viewDidLoad() { 
        super.viewDidLoad() 
    
        textView.delegate = self 
    
        activate(
         scrollView.anchor.top.constant(100), 
         scrollView.anchor.paddingHorizontally(30) 
        ) 
    
        activate(
         textView.anchor.edges 
        ) 
        } 
    
        // MARK: - NSTextDelegate 
        func textDidChange(_ notification: Notification) { 
        guard let textView = notification.object as? NSTextView else { return } 
    
        print(textView.intrinsicContentSize) 
        textView.invalidateIntrinsicContentSize() 
        } 
    } 
    
Cuestiones relacionadas