iOS 6已更新为使用UITextView进行富文本编辑(UITextView现在获得了attributedText属性,这是愚蠢的不可变属性)。以下是在NDA下的iOS 6苹果论坛上提出的一个问题,该问题可以公开,因为iOS 6现在已经公开了。。。
在UITextView中,我可以撤消任何字体更改,但不能撤消视图属性字符串副本中的替换。使用此代码时。。。
- (void) replace: (NSAttributedString*) old with: (NSAttributedString*) new
{
1. [[myView.undoManager prepareWithInvocationTarget:self] replace:new with:old];
2. old=new;
}
撤销是很有效的。
但是,如果我添加一行以使结果在视图中可见,undoManager不会像它应该的那样激发"replace:with:"方法。。。
- (void) replace: (NSAttributedString*) old with: (NSAttributedString*) new
{
1. [[myView.undoManager prepareWithInvocationTarget:self] replace:new with:old];
2. old=new;
3. myView.attributedText=[[NSAttributedString alloc] initWithAttributedString:old];
}
知道吗?我对任何替换方法都有同样的问题,无论是否使用范围,对于我试图在第"2"行使用的MutableAttributedString。。。
嗯,哇,我真的没想到会这样!我找不到解决方案,所以我开始尝试一切。。。
- (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];
}
UITextView
有undoManager
,它将免费管理撤消和重做,而不需要任何额外的代码。
替换其attributedText
将重置undoManager
(更新textStorage
中的文本及其属性对我也不起作用)。然而,我发现,在不替换attributedText
而是通过标准编辑操作(右键单击高亮显示文本>字体>粗体(Mac Catalyst))设置文本格式时,撤消和重做功能可以正常工作。
为了确保undoManager
正常工作,您只需要使用UITextView
的某些特定方法。使用其他方法可能会破坏UITextView
的撤消功能。
编辑文本
- 您需要将
UITextView
的allowsEditingTextAttributes
设置为true
,这将使UITextView
支持对attributedText
的撤消和重做
self.textView.allowsEditingTextAttributes = true
- 如果要更改
attributedText
的文本,请使用UITextInput
的replace(_:withText:)
,或UITextView
符合的UIKeyInput
的insertText(_:)
和deleteBackward()
self.textView.replace(self.textView.selectedTextRange!, withText: "test")
更新属性
如果要更改文本的属性,请改用UITextView
中的updateTextAttributes(conversionHandler:)
。
self.textView.updateTextAttributes { _ in
let font = UIFont.boldSystemFont(ofSize: 17)
let attributes: [NSAttributedString.Key: Any] = [
.font: font,
]
return attributes
}
或
self.textView.updateTextAttributes { attributes in
let newAttributes = attributes
let font = UIFont.boldSystemFont(ofSize: 17)
let newAttributes: [.font] = font
return newAttributes
}
插入附件
根据NSAttributedString
中init(attachment:)
的文档。
这是一种方便的方法,用于创建包含附件的属性字符串,该字符串使用
character
(NSTextAttachment.fcharacter)作为基字符。
如果要使用updateTextAttributes
添加附件,则应首先为附件(NSTextAttachment.character
)插入一个特殊字符(如果不使用此字符,则附件不会显示)。
例如,
let attachment = NSTextAttachment(image: image)
let specialChar = String(Character(UnicodeScalar(NSTextAttachment.character)!))
textView.insertText(specialChar)
textView.selectedRange = NSRange(location: textView.selectedRange.lowerBound-specialChar.count, length: specialChar.count)
textView.updateTextAttributes { attributes in
var newAttributes = attributes
newAttributes[.attachment] = attachment
return newAttributes
}
若要更改特定范围内的文本及其属性,请修改UITextView
的selectedRange
或selectedTextRange
。
要实现撤消和重做按钮,请检查以下答案:https://stackoverflow.com/a/50530040/8637708
我已经用Mac Catalyst进行了测试,它应该也能在iOS和iPadOS上运行。
撤销管理器在设置其"text"或"attributedText"属性后重置,这就是它不起作用的原因。我不知道这种行为是错误还是故意的。
但是,您可以使用UITextInput协议方法。
- (void)replaceRange:(UITextRange*)range with text:(NSString*)text
这很有效。