5

我想更改丰富的UITextView(iOS 6)的部分或全部属性文本,并允许用户撤销更改。在丰富的UITextView(iOS 6)中使用NSUndoManager撤消操作

阅读NSUndoManager documentation后,我尝试了第一种方式:

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

我希望撤消操作是简单:
声明此方法:

- (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]; 
    } 
} 

更改文本我UITextView通过调用:

[self setAttributedStringToTextView:mutableAttributedString]; 

但是在做完之后,NSUndoManager说它无法撤消。

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




所以,我想第二个办法:

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

声明如下:

- (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]; 
    } 
} 

,并更改文本:

[self setMyTextViewAttributedString:mutableAttributedString]; 

之后,NSUndoManager也说它无法撤消。

为什么?

请注意,用户在触发将更改属性文本的代码时正在编辑UITextView。




一种解决方法是通过UITextInput协议方法直接替换的文本。以下方法非常方便,但我还没有找到NSAttributedString的等效项。我错过了吗?

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

这里建议的黑客是模拟粘贴操作。如果可能的话,我宁愿避免这种情况(没有理由,只是觉得太肮脏,以后不会再咬我)。

+0

您是否验证过'self.textView','self.textView.attributedText'和'self.textView.undoManager'都是非'nil'? –

+0

是的。 self.textView.attributedText = newValue实际上是在用户界面中更新的。而textView.undoManager是类WebThreadSafeUndoManager的成员,并且是我的viewController的所有生命周期的同一个实例。 – Guillaume

+1

我注意到了同样的问题。我可以撤销一些操作,但不能替换为被替换的字符串。没有找到解决方法(请参阅http://stackoverflow.com/questions/12501541/uitextview-undo-manager-do-not-work-with-replacement-attributed-string-ios-6) – Denis

回答

1

我有点还是在震惊这个作品。我在这里发布了相同的答案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]; 
}