Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.1k views
in Technique[技术] by (71.8m points)

ios - Center NSTextAttachment image next to single line UILabel

I'd like to append an NSTextAttachment image to my attributed string and have it centered vertically.

I've used the following code to create my string:

NSMutableAttributedString *str = [[NSMutableAttributedString alloc] initWithString:DDLocalizedString(@"title.upcomingHotspots") attributes:attrs];
NSTextAttachment *attachment = [[NSTextAttachment alloc] init];
attachment.image = [[UIImage imageNamed:@"help.png"] imageScaledToFitSize:CGSizeMake(14.f, 14.f)];
cell.textLabel.attributedText = [str copy];

However, the image appears to align to the top of the cell's textLabel.

text attachment offset problem screenshot

How can I change the rect in which the attachment is drawn?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You can use the capHeight of the font.

Objective-C

NSTextAttachment *icon = [[NSTextAttachment alloc] init];
UIImage *iconImage = [UIImage imageNamed:@"icon.png"];
[icon setBounds:CGRectMake(0, roundf(titleFont.capHeight - iconImage.size.height)/2.f, iconImage.size.width, iconImage.size.height)];
[icon setImage:iconImage];
NSAttributedString *iconString = [NSAttributedString attributedStringWithAttachment:icon];
[titleText appendAttributedString:iconString];

Swift

let iconImage = UIImage(named: "icon.png")!
var icon = NSTextAttachment()
icon.bounds = CGRect(x: 0, y: (titleFont.capHeight - iconImage.size.height).rounded() / 2, width: iconImage.size.width, height: iconImage.size.height)
icon.image = iconImage
let iconString = NSAttributedString(attachment: icon)
titleText.append(iconString)

The attachment image is rendered on the baseline of the text. And the y axis of it is reversed like the core graphics coordinate system. If you want to move the image upward, set the bounds.origin.y to positive.

The image should be aligned vertically center with the capHeight of the text. So we need to set the bounds.origin.y to (capHeight - imageHeight)/2.

Avoiding some jagged effect on the image, we should round the fraction part of the y. But fonts and images are usually small, even 1px difference makes the image looks like misaligned. So I applied the round function before dividing. It makes the fraction part of the y value to .0 or .5

In your case, the image height is larger than the capHeight of the font. But you can use the same way. The offset y value will be negative. And it will be laid out from the below of the baseline.

enter image description here


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...