macos cocoa nstextfield autolayout
http://scottyob.com/pub/autoGrowingExample.zip

macos - conseguir un NSTextField para crecer con el texto en el diseño automático?



cocoa autolayout (3)

Estoy tratando de hacer que mi NSTextField crezca (al igual que en iChat o Adium) una vez que el usuario escribe suficiente texto para desbordar el ancho del control (como se le preguntó en esta publicación )

Impliminé la respuesta aceptada, pero parece que no puedo hacer que funcione. He cargado mi intento en http://scottyob.com/pub/autoGrowingExample.zip

Idealmente, cuando el texto crezca, la ventana que lo contiene debería crecer con él, pero estoy tratando de dar pasos aquí.


¡Resuelto! (Inspirado en https://github.com/jerrykrinock/CategoriesObjC/blob/master/NS(Attributed)String%2BGeometry/NS(Attributed)String%2BGeometrics.m )

Leer la documentación de Apple suele ser útil. Apple ha diseñado todo este diseño de texto para que sea lo suficientemente potente como para manejar todo tipo de casos extremos complicados que a veces es extremadamente útil, y a veces no.

En primer lugar, configuré el campo de texto para ajustar las líneas en el salto de palabra, por lo que en realidad obtenemos varias líneas. (Su código de ejemplo incluso tenía una instrucción if, por lo que no hizo nada cuando se desactivaba el ajuste).

El truco de esto fue notar que cuando se edita texto, se imprime mediante un ''editor de campo'' - un objeto NSTextView gran peso, propiedad de una NSWindow , que se reutiliza por lo que NSTextField es actualmente el ''primer respondedor'' (seleccionado) . NSTextView tiene un único NSTextContainer (rectángulo donde va el texto), que tiene un NSLayoutManager para diseñar el texto. Podemos preguntar al administrador de diseño cuánto espacio desea usar, para obtener la nueva altura de nuestro campo de texto.

El otro truco fue anular el método de delegado NSText - (void)textDidChange:(NSNotification *)notification para invalidar el tamaño de contenido intrínseco cuando se cambia el texto (por lo que no solo espera la actualización cuando confirma el cambio presionando return) .

La razón por la que no cellSizeForBounds como sugirió originalmente fue que no pude resolver su problema, incluso cuando se invalida el tamaño del contenido intrínseco de la celda, cellSizeForBounds: continúa devolviendo el tamaño antiguo.

Encuentra el proyecto de ejemplo en GitHub .

@interface TSTTextGrowth() { BOOL _hasLastIntrinsicSize; BOOL _isEditing; NSSize _lastIntrinsicSize; } @end @implementation TSTTextGrowth - (void)textDidBeginEditing:(NSNotification *)notification { [super textDidBeginEditing:notification]; _isEditing = YES; } - (void)textDidEndEditing:(NSNotification *)notification { [super textDidEndEditing:notification]; _isEditing = NO; } - (void)textDidChange:(NSNotification *)notification { [super textDidChange:notification]; [self invalidateIntrinsicContentSize]; } -(NSSize)intrinsicContentSize { NSSize intrinsicSize = _lastIntrinsicSize; // Only update the size if we’re editing the text, or if we’ve not set it yet // If we try and update it while another text field is selected, it may shrink back down to only the size of one line (for some reason?) if(_isEditing || !_hasLastIntrinsicSize) { intrinsicSize = [super intrinsicContentSize]; // If we’re being edited, get the shared NSTextView field editor, so we can get more info NSText *fieldEditor = [self.window fieldEditor:NO forObject:self]; if([fieldEditor isKindOfClass:[NSTextView class]]) { NSTextView *textView = (NSTextView *)fieldEditor; NSRect usedRect = [textView.textContainer.layoutManager usedRectForTextContainer:textView.textContainer]; usedRect.size.height += 5.0; // magic number! (the field editor TextView is offset within the NSTextField. It’s easy to get the space above (it’s origin), but it’s difficult to get the default spacing for the bottom, as we may be changing the height intrinsicSize.height = usedRect.size.height; } _lastIntrinsicSize = intrinsicSize; _hasLastIntrinsicSize = YES; } return intrinsicSize; } @end

Como última observación, nunca utilicé el autodiseño, las demostraciones se ven increíbles, pero cada vez que lo intento, no puedo hacerlo funcionar bien y eso complica las cosas. Sin embargo, en este caso, creo que realmente ahorró un montón de trabajo; sin él, -intrinsicContentSize no existiría, y usted posiblemente tendría que establecer el marco usted mismo, calculando el nuevo origen y el nuevo tamaño ( no demasiado difícil, pero solo más código).


La solución de Douglas Heriot solo funciona para campos de texto de ancho fijo. En mi aplicación, tengo campos de texto que quiero que crezcan tanto horizontal como verticalmente. Por lo tanto, modifiqué la solución de la siguiente manera:

AutosizingTextField.h

@interface AutosizingTextField : NSTextField { BOOL isEditing; } @end

AutosizingTextField.m

@implementation AutosizingTextField - (void)textDidBeginEditing:(NSNotification *)notification { [super textDidBeginEditing:notification]; isEditing = YES; } - (void)textDidEndEditing:(NSNotification *)notification { [super textDidEndEditing:notification]; isEditing = NO; } - (void)textDidChange:(NSNotification *)notification { [super textDidChange:notification]; [self invalidateIntrinsicContentSize]; } -(NSSize)intrinsicContentSize { if(isEditing) { NSText *fieldEditor = [self.window fieldEditor:NO forObject:self]; if(fieldEditor) { NSTextFieldCell *cellCopy = [self.cell copy]; cellCopy.stringValue = fieldEditor.string; return [cellCopy cellSize]; } } return [self.cell cellSize]; } @end

Queda un problema menor: al escribir espacios, el texto salta un poco hacia la izquierda. Sin embargo, eso no es un problema en mi aplicación, porque los campos de texto no deben contener espacios en la mayoría de los casos.


Y si desea limitar el tamaño de TextField (por ejemplo):

if (intrinsicSize.height > 100) { intrinsicSize = _lastIntrinsicSize; } else { _lastIntrinsicSize = intrinsicSize; _hasLastIntrinsicSize = YES; }

( Dif )

Una cosa con la que estoy teniendo problemas es colocar el NSTextField incrustado en un NSScrollView y hacer que funcione correctamente (especialmente dentro de un NSStackView). Vamos a ver si no sería más fácil con NSTextView en su lugar.