委托方法确实有效,但前提是附件在图像属性中有图像并且可编辑 = 否!因此,如果您从其他地方将图像粘贴到属性字符串中,则数据似乎最终存储在 fileWrapper 中,下次您将属性字符串放回 textView 时,图像属性为 nil 并且布局管理器或任何获取图像的东西从文件包装器。
在文档的某处,它确实提到 NSTextAttachment 中没有用于持久化图像属性的方法。
要对此进行测试,请尝试从 Photo 应用程序复制一张照片并将其粘贴到您的 textView 中,现在如果您按住手指,您应该会看到默认菜单弹出。现在如果你保存这个富文本,说成一个核心数据实体,然后检索它,图像属性将为 nil,但图像数据将在attachment.fileWrapper.regularFileContents
这很痛苦,我很想知道工程师的意图。所以你似乎有两个选择。
- 创建您自己的自定义 NSTextAttachment 并包含用于存档图像和其他设置的方法(请在您弄清楚这一点时告诉我如何做)
每次将字符串放回 textView 之前,您都会找到所有附件并重新创建图像属性,如下所示:
attachment.image = [UIImage imageWithData:attachment.fileWrapper.regularFileContents];
请记住,这样做的副作用是使 fileWrapper 无效。我想调整图像大小,但也要保留原始图像,这样我就不会失去完整的分辨率。我认为这样做的唯一方法可能是继承 NSTextAttachment。
编辑:
我想出了如何创建自定义 NSTextAttachments - 这是一个链接给那些感兴趣的人http://ossh.com.au/design-and-technology/software-development/implementing-rich-text-with-images-on-os -x 和 ios/
编辑 2:要在编辑模式下自定义菜单,请参阅以下 Apple 文档,问题是“touchEnded”似乎从未被调用,因此您可能不得不尝试使用 touchesBegan。小心不要干扰默认的编辑行为。
https://developer.apple.com/library/ios/documentation/StringsTextFonts/Conceptual/TextAndWebiPhoneOS/AddingCustomEditMenuItems/AddingCustomEditMenuItems.html
请注意,在下面的代码中,您需要在// selection management
注释后添加代码以确定触摸了哪个字符,检查它是否是特殊文本附件字符,然后修改编辑菜单或采取其他措施。
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *theTouch = [touches anyObject];
if ([theTouch tapCount] == 2 && [self becomeFirstResponder]) {
// selection management code goes here...
// bring up edit menu.
UIMenuController *theMenu = [UIMenuController sharedMenuController];
CGRect selectionRect = CGRectMake (currentSelection.x, currentSelection.y, SIDE, SIDE);
[theMenu setTargetRect:selectionRect inView:self];
[theMenu setMenuVisible:YES animated:YES];
}
}
或者,您可以通过添加菜单项然后修改 canPerformAction 方法来添加自定义菜单。
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
LOG(@"canPerformAction: called");
if (action == @selector(viewImage)) {
// Check the selected character is the special text attachment character
return YES;
}
return NO;
}
这是一些附加代码,但它有点挑剔。如果检测到附件,第二种方法只是禁用默认编辑菜单。
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
FLOG(@"touchesBegan:withEvent: called");
if (self.selectedRange.location != NSNotFound) {
FLOG(@" selected location is %d", self.selectedRange.location);
int ch;
if (self.selectedRange.location >= self.textStorage.length) {
// Get the character at the location
ch = [[[self textStorage] string] characterAtIndex:self.selectedRange.location-1];
} else {
// Get the character at the location
ch = [[[self textStorage] string] characterAtIndex:self.selectedRange.location];
}
if (ch == NSAttachmentCharacter) {
FLOG(@" selected character is %d, a TextAttachment", ch);
} else {
FLOG(@" selected character is %d", ch);
}
}
}
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
FLOG(@"canPerformAction: called");
FLOG(@" selected location is %d", self.selectedRange.location);
FLOG(@" TextAttachment character is %d", NSAttachmentCharacter);
if (self.selectedRange.location != NSNotFound) {
int ch;
if (self.selectedRange.location >= self.textStorage.length) {
// Get the character at the location
ch = [[[self textStorage] string] characterAtIndex:self.selectedRange.location-1];
} else {
// Get the character at the location
ch = [[[self textStorage] string] characterAtIndex:self.selectedRange.location];
}
if (ch == NSAttachmentCharacter) {
FLOG(@" selected character is %d, a TextAttachment", ch);
return NO;
} else {
FLOG(@" selected character is %d", ch);
}
// Check for an attachment
NSTextAttachment *attachment = [[self textStorage] attribute:NSAttachmentAttributeName atIndex:self.selectedRange.location effectiveRange:NULL];
if (attachment) {
FLOG(@" attachment attribute retrieved at location %d", self.selectedRange.location);
return NO;
}
else
FLOG(@" no attachment at location %d", self.selectedRange.location);
}
return [super canPerformAction:action withSender:sender];
}