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