13

这是我的问题:

我使用 Core Data 存储来自 iOS 和/或 OS X 应用程序的富文本输入,并希望粘贴到 NSTextView 或 UITextView 中的图像:a) 保留其原始分辨率,b) 显示以正确缩放以适合 textView,这意味着根据设备上视图的大小进行缩放。

目前我- (void)textStorage:(NSTextStorage *)textStorage didProcessEditing:(NSTextStorageEditActions)editedMask range:(NSRange)editedRange changeInLength:(NSInteger)delta用于查找附件,然后生成具有比例因子的图像并将其分配给 textAttachment.image 属性。

这种方法之所以有效,是因为我只是更改了比例因子并且保留了原始图像,但我相信更优雅的解决方案是使用 NSTextAttachmentContainer 子类并从中返回适当大小的 CGREct

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

所以我的问题是如何创建和插入这样的子类?

我是否使用 textStorage:didProcessEditing 来遍历每个附件并用我自己的类替换它的 NSTextAttachmentContainer,或者我可以简单地创建一个类别,然后以某种方式使用这个类别来更改默认行为。后者似乎不那么具有侵入性,但我如何让我的 textViews 自动使用这个类别?

糟糕:刚刚注意到 NSTextAttachmentContainer 是一个协议,所以我假设然后在 NSTextAttachment 上创建一个类别并覆盖上面的方法是一个选项。

嗯:不能使用 Category 来覆盖现有的类方法,所以我猜子类化是唯一的选择,在这种情况下,我如何让 UITextView 使用我的附件子类,或者我是否必须遍历 attributesString 以替换所有 NSTextAttachments MYTextAttachment 的实例。将这个字符串在 OS X 上解压成默认的 OS X NSTextAttachment(不同于 iOS 类)会有什么影响?

4

2 回答 2

17

基于这篇优秀的文章,如果你想利用

- (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 时都会调用它。

希望它有所帮助,即使它不能回答您问题的各个方面。

于 2014-01-15T23:10:18.187 回答
3

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)。

于 2016-12-18T22:54:32.427 回答