IOS7TextKit-如何插入与文本内联的图像?

我试图使用 UITextView 获得以下效果:

enter image description here

基本上,我想在文本之间插入一个图像。图像只需占用一行空间,因此没有包装的必要。

我试着在子视图中添加一个 UIView:

UIView *pictureView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 25, 25)];
[pictureView setBackgroundColor:[UIColor redColor]];
[self.textView addSubview:pictureView];

但它似乎漂浮在文本和覆盖它。

我读了一些关于 排除路径的文章,它似乎是实现这一点的一种方法。但是,我不想绝对定位图像-相反,它应该与文本一起流动(类似于 <span>在 HTML 中的行为)。

60049 次浏览

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.

You'll need to use an attributed string and add the image as instance of 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];

@bilobatum's code converted to Swift for those in need:

let attributedString = NSMutableAttributedString(string: "like after")


let textAttachment = NSTextAttachment()


textAttachment.image = UIImage(named: "whatever.png")


let attrStringWithImage = NSAttributedString(attachment: textAttachment)


attributedString.replaceCharacters(in: NSMakeRange(4, 1), with: attrStringWithImage)

Expanding on @bilobatum's answer, and using this category from another question. I cooked this up:

Usage:

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;

Implementation:

@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 enter image description here

let attachment = NSTextAttachment()
attachment.image = UIImage(named: "qrcode")


let firstString = NSMutableAttributedString(string: "scan the ")
let iconString = NSAttributedString(attachment: attachment)
let secondString = NSAttributedString(string: "QR code received on your phone.")


firstString.append(iconString)
firstString.append(secondString)
    

self.textLabel.attributedText = firstString