【问题标题】:Copy NSAttributedString in UIPasteBoard在 UIPasteBoard 中复制 NSAttributedString
【发布时间】:2012-09-18 00:55:07
【问题描述】:

如何在粘贴板中复制 NSAttributedString,以允许用户粘贴或以编程方式粘贴(使用 - (void)paste:(id)sender,来自 UIResponderStandardEditActions 协议)。

我试过了:

UIPasteboard *pasteBoard = [UIPasteboard generalPasteboard];
[pasteBoard setValue:attributedString forPasteboardType:(NSString *)kUTTypeRTF];

但是这次崩溃是:

-[UIPasteboard setValue:forPasteboardType:]: value is not a valid property list type'

这是意料之中的,因为 NSAttributedString 不是属性列表值。

如果用户在我的应用中粘贴粘贴板的内容,我想保留属性字符串的所有标准和自定义属性。

【问题讨论】:

标签: ios uikit copy-paste nsattributedstring uipasteboard


【解决方案1】:

我发现当我(作为应用程序的用户)将富文本从 UITextView 复制到粘贴板时,粘贴板包含两种类型:

"public.text",
"Apple Web Archive pasteboard type

基于此,我在 UIPasteboard 上创建了一个方便的类别。
(大量使用来自this answer 的代码)。

它有效,但是:
转换为 html 格式意味着我将丢失自定义属性。我们很乐意接受任何干净的解决方案。

文件 UIPasteboard+AttributedString.h:

@interface UIPasteboard (AttributedString)

- (void) setAttributedString:(NSAttributedString *)attributedString;

@end

文件 UIPasteboard+AttributedString.m:

#import <MobileCoreServices/UTCoreTypes.h>

#import "UIPasteboard+AttributedString.h"

@implementation UIPasteboard (AttributedString)

- (void) setAttributedString:(NSAttributedString *)attributedString {
    NSString *htmlString = [attributedString htmlString]; // This uses DTCoreText category NSAttributedString+HTML - https://github.com/Cocoanetics/DTCoreText
    NSDictionary *resourceDictionary = @{ @"WebResourceData" : [htmlString dataUsingEncoding:NSUTF8StringEncoding],
    @"WebResourceFrameName":  @"",
    @"WebResourceMIMEType" : @"text/html",
    @"WebResourceTextEncodingName" : @"UTF-8",
    @"WebResourceURL" : @"about:blank" };



    NSDictionary *htmlItem = @{ (NSString *)kUTTypeText : [attributedString string],
        @"Apple Web Archive pasteboard type" : @{ @"WebMainResource" : resourceDictionary } };

    [self setItems:@[ htmlItem ]];
}


@end

只实现了setter。如果您想编写 getter 和/或将其放在 GitHub 上,请成为我的客人 :)

【讨论】:

  • @H2CO3 谢谢 :) 更新了答案。
  • 不使用 DTCoreText。通过以下方式将其转换为 HTML: NSDictionary *documentAttributes = [NSDictionary dictionaryWithObjectsAndKeys:NSHTMLTextDocumentType, NSDocumentTypeDocumentAttribute, nil]; \n NSData *htmlData = [attributedString dataFromRange:NSMakeRange(0, attributesString.length) documentAttributes:documentAttributes error:NULL]; \n NSString *htmlString = [[NSString alloc] initWithData:htmlData encoding:NSUTF8StringEncoding];
【解决方案2】:

不涉及 HTML,干净的解决方案是将 NSAttributedString 作为 RTF(加上纯文本后备)插入粘贴板:

- (void)setAttributedString:(NSAttributedString *)attributedString {
    NSData *rtf = [attributedString dataFromRange:NSMakeRange(0, attributedString.length)
                               documentAttributes:@{NSDocumentTypeDocumentAttribute: NSRTFTextDocumentType}
                                            error:nil];
    self.items = @[@{(id)kUTTypeRTF: [[NSString alloc] initWithData:rtf encoding:NSUTF8StringEncoding],
                     (id)kUTTypeUTF8PlainText: attributedString.string}];
}

斯威夫特 5

import MobileCoreServices

public extension UIPasteboard {
    func set(attributedString: NSAttributedString) {
        do {
            let rtf = try attributedString.data(from: NSMakeRange(0, attributedString.length), documentAttributes: [NSAttributedString.DocumentAttributeKey.documentType: NSAttributedString.DocumentType.rtf])
            items = [[kUTTypeRTF as String: NSString(data: rtf, encoding: String.Encoding.utf8.rawValue)!, kUTTypeUTF8PlainText as String: attributedString.string]]
        } catch {
        }
    }
}

【讨论】:

    【解决方案3】:

    很简单:

      #import <MobileCoreServices/UTCoreTypes.h>
    
      NSMutableDictionary *item = [[NSMutableDictionary alloc] init];
    
      NSData *rtf = [attributedString dataFromRange:NSMakeRange(0, attributedString.length)
                                 documentAttributes:@{NSDocumentTypeDocumentAttribute: NSRTFDTextDocumentType}
                                              error:nil];
    
      if (rtf) {
        [item setObject:rtf forKey:(id)kUTTypeFlatRTFD];
      }
    
      [item setObject:attributedString.string forKey:(id)kUTTypeUTF8PlainText];
    
      UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
      pasteboard.items = @[item];
    

    【讨论】:

      【解决方案4】:

      OSX 中的粘贴板管理器可以在很多文本和图像类型之间自动转换。

      对于富文本类型,您通常会将 RTF 放入粘贴板。您可以从属性字符串创建 RTF 表示,反之亦然。请参阅“NSAttributedString 应用程序工具包添加参考”。

      如果您还包含图像,则使用 RTFd 而不是 RTF 风格。

      我不知道这些的 MIME 类型(我习惯于 Carbon Pasteboard API,而不是 Cocoa 的),但您可以使用 UTType API 在 UTI、Pboard 和 MIME 类型之间进行转换。

      RTF 的 UTI 是“public.rtf”,RTFd 的 UTI 是“com.apple.flat-rtfd”。

      【讨论】:

      • 糟糕——那个小小的“ios”标签很容易被忽略。而且 iOS 似乎没有内置 RTF 转换功能。太糟糕了。
      • 同意。通常,当标签是查看它的唯一方式时,我会在问题中明确说明它。我没有,因为我认为 UIPasteboard 就足够了。抱歉没有说得更清楚。
      • 哦,UIPasteboard。是的,我本可以注意到那个。我在 iOS 和 OSX 上工作了很多,以至于我一直在混淆它们命名略有不同的类 :)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-02-10
      • 1970-01-01
      • 1970-01-01
      • 2015-02-03
      • 1970-01-01
      • 2015-03-03
      • 1970-01-01
      相关资源
      最近更新 更多