5

Quiero cambiar todo o parte del texto atribuido de una rica UITextView (iOS 6) y permitir al usuario deshacer el cambio.Deshacer operación con NSUndoManager en rich UITextView (iOS 6)

Después de leer NSUndoManager documentation, probé la primera forma:

“Simple undo” based on a simple selector with a single object argument. 

que esperaba una operación de deshacer para ser tan simple como:
Declarar este método:

- (void)setAttributedStringToTextView:(NSAttributedString *)newAttributedString { 

    NSAttributedString *currentAttributedString = self.textView.attributedText; 

    if (! [currentAttributedString isEqualToAttributedString:newAttributedString]) { 
     [self.textView.undoManager registerUndoWithTarget:self 
            selector:@selector(setAttributedStringToTextView:) 
             object:currentAttributedString]; 
     [self.textView.undoManager setActionName:@"Attributed string change"]; 
     [self.textView setAttributedText:newAttributedString]; 
    } 
} 

Cambiar el texto en mi UITextView llamando al:

[self setAttributedStringToTextView:mutableAttributedString]; 

Pero después de hacer eso, NSUndoManager dice que no puede deshacer.

NSLog(@"Can undo: %d", [self.textView.undoManager canUndo]); 
// Prints: "Can undo: 0" 




así que traté de la segunda manera:

“Invocation-based undo” which uses an NSInvocation object. 

nuevas de esto:

- (void)setMyTextViewAttributedString:(NSAttributedString *)newAttributedString { 

     NSAttributedString *currentAttributedString = [self.textView attributedText]; 
    if (! [currentAttributedString isEqualToAttributedString:newAttributedString]) { 
     [[self.textView.undoManager prepareWithInvocationTarget:self] 
     setMyTextViewAttributedString:currentAttributedString]; 
     [self.textView.undoManager setActionName:@"Attributed string change"]; 
     [self.textView setAttributedText:newAttributedString]; 
    } 
} 

y cambiar el texto con:

[self setMyTextViewAttributedString:mutableAttributedString]; 

Después de eso, NSUndoManager también dice que no se puede deshacer.

¿Por qué?

Tenga en cuenta que el usuario está editando el UITextView al activar el código que cambiará el texto atribuido.




Una solución sería la de sustituir el texto directamente a través del método protocolo UITextInput. El siguiente método es bastante conveniente, pero no he encontrado un equivalente para NSAttributedString. ¿Lo extrañé?

- (void)replaceRange:(UITextRange *)range withText:(NSString *)text 

Un truco sugerido aquí es simular una operación de pegado. Si es posible, preferiría evitar esto (no hay razón todavía, solo me siento demasiado sucio para no volver a morderme más tarde).

+0

¿Has verificado que 'self.textView',' self.textView.attributedText', y 'self.textView.undoManager' no son' 'nil'? –

+0

Sí. self.textView.attributedText = newValue se actualiza realmente en la interfaz de usuario. Y textView.undoManager es miembro de la clase WebThreadSafeUndoManager, y es la misma instancia para todo el ciclo de vida de mi viewController. – Guillaume

+1

Noté el mismo problema. Puedo deshacer algunas operaciones pero no un reemplazo de attributeString. No se encontró ninguna solución (ver http://stackoverflow.com/questions/12501541/uitextview-undo-manager-do-not-work-with-replacement-attributed-string-ios-6) – Denis

Respuesta

1

Todavía estoy en estado de shock esto funciona. Publiqué la misma respuesta aquí UITextView undo manager do not work with replacement attributed string (iOS 6).

- (void)applyAttributesToSelection:(NSDictionary*)attributes { 
    UITextView *textView = self.contentCell.textView; 

    NSRange selectedRange = textView.selectedRange; 
    UITextRange *selectedTextRange = textView.selectedTextRange; 
    NSAttributedString *selectedText = [textView.textStorage attributedSubstringFromRange:selectedRange]; 

    [textView.undoManager beginUndoGrouping]; 
    [textView replaceRange:selectedTextRange withText:selectedText.string]; 
    [textView.textStorage addAttributes:attributes range:selectedRange]; 
    [textView.undoManager endUndoGrouping]; 

    [textView setTypingAttributes:attributes]; 
} 
Cuestiones relacionadas