How to subclass NSTextAttachment?

前端 未结 2 1217
-上瘾入骨i
-上瘾入骨i 2020-12-13 07:35

Here is my problem:

I use Core Data to store rich text input from iOS and/or OS X apps and would like images pasted into the NSTextView or UITextView to: a) retain t

相关标签:
2条回答
  • 2020-12-13 08:09

    Based on this excellent article, if you want to make use of

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

    to scale an image text attachment, you have to create your own subclass of NSTextAttachment

    @interface MYTextAttachment : NSTextAttachment 
    @end
    

    with the scale operation in the implementation:

    @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
    

    based on

    lineFrag.size.width
    

    which give you (or what I have understood as) the width taken by the textView on which you have (will) set the attributed text "embedding" your custom text attachment.

    Once the subclass of NSTextAttachment created, all you have to do is make use of it. Create an instance of it, set an image, then create a new attributed string with it and append it to a NSMutableAttributedText per example:

    MYTextAttachment* _textAttachment = [MYTextAttachment new];
    _textAttachment.image = [UIImage ... ];
    
    [_myMutableAttributedString appendAttributedString:[NSAttributedString attributedStringWithAttachment:_immediateTextAttachment]];
    

    For info it seems that

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

    is called whenever the textview is asked to be relayout-ed.

    Hope it helps, even though it doesn't answer every aspect of your problem.

    0 讨论(0)
  • 2020-12-13 08:14

    Swift 3 (based on @Bluezen's answer):

    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
        }
    
    }
    

    Note that I am scaling based on height, as I was getting a lineFrag width value of 10000000 in my particular use case. Also note that I replaced scalingFactor = ... with scalingFactor *= ... so that I could use an additional, non-unity scaling factor (0.8 in this case).

    0 讨论(0)
提交回复
热议问题