iOS 7 TextKit - How to insert images inline with text?
iOS 7 TextKit - How to insert images inline with text?
I am trying to get the following effect using a UITextView:
Basically I want to insert an image between text. The image can simply just take up 1 row of space so there is no wrapping necessary.
I tried just adding a UIView to the subview:
UIView *pictureView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 25, 25)];
[pictureView setBackgroundColor:[UIColor redColor]];
[self.textView addSubview:pictureView];
But it seems to float over the text and cover it.
I did a bit of reading on exclusion paths which appears to be one way of implementing this. However, I don't want to absolutely position the image - instead, it should flow with the text (similar to how <span>
behaves in HTML).
<span>
Amazing that I just watched the Royal Rumble 2011 this morning (where your image was grabbed from) via the WWE network and here I am happening upon this question today.
– bpapa
Mar 2 '14 at 15:56
Heya, have you got an example of some working code involving TextAttachment?
– fatuhoku
Jun 24 '14 at 8:56
5 Answers
5
You'll need to use an attributed string and add the image as instance of NSTextAttachment
:
NSTextAttachment
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:@"like after"];
NSTextAttachment *textAttachment = [[NSTextAttachment alloc] init];
textAttachment.image = [UIImage imageNamed:@"whatever.png"];
NSAttributedString *attrStringWithImage = [NSAttributedString attributedStringWithAttachment:textAttachment];
[attributedString replaceCharactersInRange:NSMakeRange(4, 1) withAttributedString:attrStringWithImage];
I think this is the closest answer so far. Is it possible to use this same technique with the UIView instead of UIImage?
– Andy Hin
Jan 5 '14 at 6:43
This is not displaying the images when using the resulting string in UITextView
– DeepK SOreadytohelp
Mar 28 '14 at 11:21
How do i resize the NSTextAttachment?
– jsetting32
Dec 18 '14 at 9:52
@bilobatum, I want to add more than one images into textview. So how can i add?
– Diken Shah
Jun 16 '15 at 11:00
` [attributedString insertAttributedString:textAttachment atIndex:4]` is better than
replaceCharactersInRange
– Dawn Song
Oct 14 '16 at 13:47
replaceCharactersInRange
You could try using NSAttributedString and NSTextAttachment. Take a look at the following link for more details on customising the NSTextAttachment in order to resize the image.
http://ossh.com.au/design-and-technology/software-development/implementing-rich-text-with-images-on-os-x-and-ios/
In my example I resize the image to fit the width, in your case you may want to resize the image to match the line height.
I think this is the closest answer so far. Is it possible to use this same technique with the UIView instead of UIImage?
– Andy Hin
Jan 5 '14 at 7:04
You may be able to with some major work on your own custom classes. NSTextAttachment has a default image attribute and the attachment is stored as part of the NSAttributedString. You probably could create your own subclasses and store whatever you want. I think display is limited to displaying an image so not sure a UIView would be useful. As I recall the layoutManager expects an image.
– Duncan Groenewald
Jan 5 '14 at 13:36
@AndyHin I haven't tested this myself but one option is possibly to render your
UIView
to a UIImage
and then add it as an NSTextAttachment
. In order to render the view to an image check out this question: http://stackoverflow.com/questions/4334233/how-to-capture-uiview-to-uiimage-without-loss-of-quality-on-retina-display?lq=1– Michael Gaylord
Mar 24 '14 at 12:53
UIView
UIImage
NSTextAttachment
Any new developments with this?
– fatuhoku
Jun 24 '14 at 10:15
@bilobatum's code converted to Swift for those in need:
var attributedString = NSMutableAttributedString(string: "like after")
var textAttachment = NSTextAttachment()
textAttachment.image = UIImage(named: "whatever.png")
var attrStringWithImage = NSAttributedString.attributedStringWithAttachment(textAttachment)
attributedString.replaceCharactersInRange(NSMakeRange(4, 1), withAttributedString: attrStringWithImage)
Just a friendly remark: You can drop the type declarations of the variables.
– Lucifer
Jun 6 '16 at 16:59
Expanding on @bilobatum's answer, and using this category from another question. I cooked this up:
UILabel *labelWithImage = [UILabel new];
labelWithImage.text = @"Tap [new-button] to make a new thing!";
NSAttributedString *stringWithImage = [labelWithImage.attributedText attributedStringByReplacingOccurancesOfString:@"[new-button]" withImage:[UIImage imageNamed:@"MyNewThingButtonImage"] scale:0];
labelWithImage.attributedText = stringWithImage;
@interface NSMutableAttributedString (InlineImage)
- (void)replaceCharactersInRange:(NSRange)range withInlineImage:(UIImage *)inlineImage scale:(CGFloat)inlineImageScale;
@end
@interface NSAttributedString (InlineImages)
- (NSAttributedString *)attributedStringByReplacingOccurancesOfString:(NSString *)string withInlineImage:(UIImage *)inlineImage scale:(CGFloat)inlineImageScale;
@end
.
@implementation NSMutableAttributedString (InlineImages)
- (void)replaceCharactersInRange:(NSRange)range withInlineImage:(UIImage *)inlineImage scale:(CGFloat)inlineImageScale {
if (floorf(inlineImageScale) == 0)
inlineImageScale = 1.0f;
// Create resized, tinted image matching font size and (text) color
UIImage *imageMatchingFont = [inlineImage imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
{
// Font size
NSDictionary *attributesForRange = [self attributesAtIndex:range.location effectiveRange:nil];
UIFont *fontForRange = [attributesForRange valueForKey:NSFontAttributeName];
CGSize imageSizeMatchingFontSize = CGSizeMake(inlineImage.size.width * (fontForRange.capHeight / inlineImage.size.height), fontForRange.capHeight);
// Some scaling for prettiness
CGFloat defaultScale = 1.4f;
imageSizeMatchingFontSize = CGSizeMake(imageSizeMatchingFontSize.width * defaultScale, imageSizeMatchingFontSize.height * defaultScale);
imageSizeMatchingFontSize = CGSizeMake(imageSizeMatchingFontSize.width * inlineImageScale, imageSizeMatchingFontSize.height * inlineImageScale);
imageSizeMatchingFontSize = CGSizeMake(ceilf(imageSizeMatchingFontSize.width), ceilf(imageSizeMatchingFontSize.height));
// Text color
UIColor *textColorForRange = [attributesForRange valueForKey:NSForegroundColorAttributeName];
// Make the matching image
UIGraphicsBeginImageContextWithOptions(imageSizeMatchingFontSize, NO, 0.0f);
[textColorForRange set];
[inlineImage drawInRect:CGRectMake(0 , 0, imageSizeMatchingFontSize.width, imageSizeMatchingFontSize.height)];
imageMatchingFont = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
// Text attachment with image
NSTextAttachment *textAttachment = [NSTextAttachment new];
textAttachment.image = imageMatchingFont;
NSAttributedString *imageString = [NSAttributedString attributedStringWithAttachment:textAttachment];
[self replaceCharactersInRange:range withAttributedString:imageString];
}
@end
@implementation NSAttributedString (InlineImages)
- (NSAttributedString *)attributedStringByReplacingOccurancesOfString:(NSString *)string withInlineImage:(UIImage *)inlineImage scale:(CGFloat)inlineImageScale {
NSMutableAttributedString *attributedStringWithImages = [self mutableCopy];
[attributedStringWithImages.string enumerateOccurancesOfString:string usingBlock:^(NSRange substringRange, BOOL *stop) {
[attributedStringWithImages replaceCharactersInRange:substringRange withInlineImage:inlineImage scale:inlineImageScale];
}];
return [attributedStringWithImages copy];
}
@end
Problem solution in simple example is
let attachment = NSTextAttachment()
attachment.image = UIImage(named: "qrcode");
let iconStringdString = NSAttributedString(attachment: attachment)
let fString = NSMutableAttributedString(string: "scan the ")
let sString = NSAttributedString(string: "QR code received on your phone.")
fString.append(iconStringdString)
fString.append(sString)
self.textLabel.attributedText = fString
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
A few of the answers mention using the image properties on NSTextAttachment and NSTextField but I want to mention that I need a solution which allows me to append a UIView.
– Andy Hin
Jan 5 '14 at 6:01