5

Tôi muốn thay đổi một số hoặc tất cả văn bản được phân bổ của UITextView phong phú (iOS 6) và cho phép người dùng hoàn tác thay đổi.Hoàn tác thao tác với NSUndoManager trong UITextView phong phú (iOS 6)

Sau khi đọc NSUndoManager documentation, tôi đã thử cách thứ nhất:

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

tôi mong đợi một hoạt động hoàn tác để thể đơn giản như:
Khai báo phương pháp này:

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

Thay đổi văn bản trong tôi UITextView bằng cách gọi:

[self setAttributedStringToTextView:mutableAttributedString]; 

Nhưng sau khi làm điều đó, NSUndoManager nói rằng nó không thể hoàn tác.

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




Vì vậy, tôi đã cố gắng cách thứ hai:

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

Khai báo này:

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

và thay đổi văn bản với:

[self setMyTextViewAttributedString:mutableAttributedString]; 

Sau đó, NSUndoManager cũng cho biết nó không thể hoàn tác.

Tại sao?

Lưu ý rằng người dùng đang chỉnh sửa UITextView khi kích hoạt mã sẽ thay đổi văn bản được phân bổ.




Một cách giải quyết sẽ được thay thế văn bản trực tiếp thông qua phương pháp giao thức UITextInput. Phương pháp sau đây khá thuận tiện, nhưng tôi đã không tìm thấy một tương đương cho NSAttributedString. Tôi đã bỏ lỡ nó?

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

Một đề xuất được đề xuất ở đây là mô phỏng thao tác dán. Nếu có thể, tôi muốn tránh điều này (không có lý do nào được nêu ra, chỉ cảm thấy quá bẩn để không trở lại cắn tôi sau này).

+0

Bạn đã xác minh rằng 'self.textView',' self.textView.attributedText' và 'self.textView.undoManager' đều không phải là 'nil'? –

+0

Có. self.textView.attributedText = newValue thực sự được cập nhật trong giao diện người dùng. Và textView.undoManager là thành viên của lớp WebThreadSafeUndoManager, và là cùng một cá thể cho tất cả vòng đời của viewController của tôi. – Guillaume

+1

Tôi nhận thấy cùng một vấn đề. Tôi có thể hoàn tác một số thao tác nhưng không thể thay thế attributedString. Không tìm thấy giải pháp thay thế (xem http://stackoverflow.com/questions/12501541/uitextview-undo-manager-do-not-work-with-replacement-attributed-string-ios-6) – Denis

Trả lời

1

Tôi vẫn đang bị sốc khi làm việc này. Tôi đã đăng câu trả lời tương tự ở đây 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]; 
}