Как подкласс NSTextAttachment?

вот моя проблема:

Я использую основные данные для хранения ввода богатого текста из приложений iOS и / или OS X и хотел бы, чтобы изображения вставлялись в NSTextView или UITextView: а) сохранить первоначальное разрешение и b) на дисплее масштабируется, чтобы соответствовать textView правильно, что означает масштабирование на основе размера представления на устройстве.

В настоящее время я использую - (void)textStorage:(NSTextStorage *)textStorage didProcessEditing:(NSTextStorageEditActions)editedMask range:(NSRange)editedRange changeInLength:(NSInteger)delta искать вложения, а затем генерировать изображение с масштабным коэффициентом и назначать его textAttachment.атрибут изображения.

этот вид работает, потому что я просто меняю масштабный коэффициент, и исходное изображение сохраняется, но я считаю, что более элегантным решением было бы использовать подкласс NSTextAttachmentContainer и вернуть из этого соответствующий размер CGREct с

- (CGRect)attachmentBoundsForTextContainer:(NSTextContainer *)textContainer proposedLineFragment:(CGRect)lineFrag glyphPosition:(CGPoint)position characterIndex:(NSUInteger)charIndex

Итак, мой вопрос в том, как создать и вставить такой подкласс ?

использую ли я textStorage: didProcessEditing для итерации по каждому вложению и замены его NSTextAttachmentContainer с собственным классом, или я могу просто создать Категорию, а затем каким-то образом использовать эту категорию для изменения поведения по умолчанию. Последнее кажется гораздо менее навязчивым, но как я могу заставить мои textViews автоматически использовать эту категорию?

Oops: только что заметил, что nstextattachmentcontainer-это протокол, поэтому я предполагаю, что создание категории на NSTextAttachment и переопределение метода выше-это опция.

Mmm: нельзя использовать категорию для переопределения существующий метод класса, поэтому я предполагаю, что подклассы-это единственный вариант, в котором я могу получить UITextView для использования моего подкласса вложений или мне нужно перебирать attributedString, чтобы заменить все nstextattachments экземплярами MYTextAttachment. И каково будет влияние распаковки этой строки на OS X, скажем, по умолчанию OS X NSTextAttachment (который отличается от класса iOS) ?

2 ответов


основываясь на этом отличная статья, если вы хотите использовать

- (CGRect)attachmentBoundsForTextContainer:(NSTextContainer *)textContainer proposedLineFragment:(CGRect)lineFrag glyphPosition:(CGPoint)position characterIndex:(NSUInteger)charIndex

чтобы масштабировать вложение текста изображения, вы должны создать свой собственный подкласс NSTextAttachment

@interface MYTextAttachment : NSTextAttachment 
@end

с операцией масштаба в реализации:

@implementation MYTextAttachment

- (CGRect)attachmentBoundsForTextContainer:(NSTextContainer *)textContainer proposedLineFragment:(CGRect)lineFrag glyphPosition:(CGPoint)position characterIndex:(NSUInteger)charIndex {
    CGFloat width = lineFrag.size.width;

    // Scale how you want
    float scalingFactor = 1.0;   
    CGSize imageSize = [self.image size];   
    if (width < imageSize.width)
        scalingFactor = width / imageSize.width;
    CGRect rect = CGRectMake(0, 0, imageSize.width * scalingFactor, imageSize.height * scalingFactor);

    return rect;
}
@end

на основе

lineFrag.size.width

которые дают вам (или то, что я понял как) ширину, занятую textView, на котором вы (будете) установить приписываемый текст "встраивание" вашего пользовательского текста привязанность.

как только подкласс NSTextAttachment создан, все, что вам нужно сделать, это использовать его. Создайте его экземпляр, установите изображение, затем создайте с ним новую приписываемую строку и добавьте ее в nsmutableattributedtext на примере:

MYTextAttachment* _textAttachment = [MYTextAttachment new];
_textAttachment.image = [UIImage ... ];

[_myMutableAttributedString appendAttributedString:[NSAttributedString attributedStringWithAttachment:_immediateTextAttachment]];

для информации кажется, что

 - (CGRect)attachmentBoundsForTextContainer:(NSTextContainer *)textContainer proposedLineFragment:(CGRect)lineFrag glyphPosition:(CGPoint)position characterIndex:(NSUInteger)charIndex 

вызывается всякий раз, когда textview просят быть relayout-ed.

надеюсь, что это поможет, хотя это не отвечает на все аспекты вашей проблемы.


Swift 3 (основан на @Bluezen это ответ):

class MyTextAttachment : NSTextAttachment {

    override func attachmentBounds(for textContainer: NSTextContainer?, proposedLineFragment lineFrag: CGRect, glyphPosition position: CGPoint, characterIndex charIndex: Int) -> CGRect {

        guard let image = self.image else {
            return CGRect.zero
        }

        let height = lineFrag.size.height

        // Scale how you want
        var scalingFactor = CGFloat(0.8)
        let imageSize = image.size
        if height < imageSize.height {
            scalingFactor *= height / imageSize.height
        }
        let rect = CGRect(x: 0, y: 0, width: imageSize.width * scalingFactor, height: imageSize.height * scalingFactor)

        return rect
    }

}

обратите внимание, что я масштабируюсь на основе высоты, так как я получал значение ширины lineFrag 10000000 в моем конкретном случае использования. Также обратите внимание, что Я заменил scalingFactor = ... С scalingFactor *= ... чтобы я мог использовать дополнительный, не единичный масштабирующий фактор (в этом случае 0.8).