Скопируйте NSAttributedString в UIPasteBoard

Как скопировать 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 не является значением списка свойств.

Если пользователь вставляет содержимое монтажного стола в мое приложение, я хотел бы сохранить все стандарты и настраиваемые атрибуты строки с атрибутами.


person Guillaume    schedule 26.09.2012    source источник
comment
Сделал некоторые идеи в UIPasteBoard и NSAttributedString, может быть ценным: stackoverflow.com/a/38211885/1054573   -  person Leonard Pauli    schedule 05.07.2016


Ответы (4)


Я обнаружил, что когда я (как пользователь приложения) копирую форматированный текст из UITextView в монтажный стол, монтажный стол содержит два типа:

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

На основании этого я создал удобную категорию на UIPasteboard.
(С интенсивным использованием кода из этого ответа).

Это работает, но:
Преобразование в формат 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

Только реализованный сеттер. Если вы хотите написать геттер и / или разместить его на GitHub, будь моим гостем :)

person Guillaume    schedule 26.09.2012
comment
@ H2CO3 Спасибо :) Обновил ответ. - person Guillaume; 26.09.2012
comment
DTCoreText не используется. Преобразуйте это в HTML следующим образом: NSDictionary * documentAttributes = [NSDictionary dictionaryWithObjectsAndKeys: NSHTMLTextDocumentType, NSDocumentTypeDocumentAttribute, nil]; \ n NSData * htmlData = [attributedString dataFromRange: NSMakeRange (0, attributedString.length) documentAttributes: documentAttributes error: NULL]; \ n NSString * htmlString = [[NSString alloc] initWithData: кодировка htmlData: NSUTF8StringEncoding]; - person Muzammil; 08.09.2014

Подход @Gillaume с использованием HTML у меня не работает (по крайней мере, в iOS 7.1 beta 5).

Более чистое решение - вставить NSAttributedStrings как 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}];
}

Swift 2.3

public extension UIPasteboard {
  public func set(attributedString: NSAttributedString?) {

    guard let attributedString = attributedString else {
      return
    }

    do {
      let rtf = try attributedString.dataFromRange(NSMakeRange(0, attributedString.length), documentAttributes: [NSDocumentTypeDocumentAttribute: NSRTFTextDocumentType])
      items = [[kUTTypeRTF as String: NSString(data: rtf, encoding: NSUTF8StringEncoding)!, kUTTypeUTF8PlainText as String: attributedString.string]]

    } catch {

    }
  }
}

Swift 3

import MobileCoreServices
public extension UIPasteboard {
  public func set(attributedString: NSAttributedString?) {

    guard let attributedString = attributedString else {
      return
    }

    do {
      let rtf = try attributedString.data(from: NSMakeRange(0, attributedString.length), documentAttributes: [NSDocumentTypeDocumentAttribute: NSRTFTextDocumentType])
      items = [[kUTTypeRTF as String: NSString(data: rtf, encoding: String.Encoding.utf8.rawValue)!, kUTTypeUTF8PlainText as String: attributedString.string]]

    } catch {

    }
  }
}
person Ortwin Gentz    schedule 20.02.2014

Это довольно просто:

  #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];
person Valentin Shergin    schedule 17.11.2016

Диспетчер монтажного стола в OSX может автоматически конвертировать между множеством текстовых и графических типов.

Для форматированных текстовых типов вы обычно помещаете RTF в монтажный стол. Вы можете создать RTF-представление из атрибутированной строки и наоборот. См. «Справочник по дополнениям набора приложений NSAttributedString».

Если у вас также есть изображения, используйте RTFd вместо RTF.

Я не знаю типов MIME для них (я привык к Carbon Pasteboard API, а не к Cocoa), но вы можете конвертировать между UTI, Pboard и MIME-типами, используя UTType API.

UTI для RTF - это «public.rtf», для RTFd - «com.apple.flat-rtfd».

person Thomas Tempelmann    schedule 11.03.2013
comment
К сожалению, этот маленький тег ios легко не заметить. А в iOS, похоже, нет встроенного преобразования RTF. Облом. - person Thomas Tempelmann; 12.03.2013
comment
Согласовано. Обычно, когда тег - единственный способ увидеть его, я указываю это в вопросе. Я не сделал этого, потому что думал, что UIPasteboard будет достаточно. Извините за неясность. - person Guillaume; 12.03.2013
comment
Ой, UIPasteboard. Да, я мог заметить это. Я так много работаю над iOS и OSX, что все время путаю их классы с немного разными названиями :) - person Thomas Tempelmann; 13.03.2013