在单行UILabel旁边的NSTextAttachment图像中心

我想追加一个NSTextAttachment图像到我的属性string,并让它垂直居中。

我用下面的代码来创build我的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]; 

但是,图像似乎alignment到单元格的textLabel的顶部。

在这里输入图像说明

我怎样才能改变附件绘制的矩形?

您可以通过NSTextAttachment并重载attachmentBoundsForTextContainer:proposedLineFragment:glyphPosition:characterIndex:来更改矩形attachmentBoundsForTextContainer:proposedLineFragment:glyphPosition:characterIndex: 例:

 - (CGRect)attachmentBoundsForTextContainer:(NSTextContainer *)textContainer proposedLineFragment:(CGRect)lineFrag glyphPosition:(CGPoint)position characterIndex:(NSUInteger)charIndex { CGRect bounds; bounds.origin = CGPointMake(0, -5); bounds.size = self.image.size; return bounds; } 

这不是一个完美的解决scheme。 你必须找出Y的原点,如果你改变字体或图标的大小,你可能会想改变Y的起源。 但我找不到更好的方法,除了把图标放在单独的图像视图中(这有其自身的缺点)。

尝试- [NSTextAttachment bounds] 。 不需要子类。

对于上下文,我正在渲染一个UILabel作为附件图像,然后像这样设置边界: attachment.bounds = CGRectMake(0, self.font.descender, attachment.image.size.width, attachment.image.size.height)以及标签图像中的文本基线和属性string中的文本根据需要排列。

我find了一个完美的解决scheme,虽然对我来说就像一个魅力,但是你必须自己尝试一下(可能常常取决于设备的分辨率,也许不pipe怎样;)

 func textAttachment(fontSize: CGFloat) -> NSTextAttachment { let font = UIFont.systemFontOfSize(fontSize) //set accordingly to your font, you might pass it in the function let textAttachment = NSTextAttachment() let image = //some image textAttachment.image = image let mid = font.descender + font.capHeight textAttachment.bounds = CGRectIntegral(CGRect(x: 0, y: font.descender - image.size.height / 2 + mid + 2, width: image.size.width, height: image.size.height)) return textAttachment } 

应该工作,不应该以任何方式模糊(感谢CGRectIntegral

关于什么:

 CGFloat offsetY = -10.0; NSTextAttachment *attachment = [NSTextAttachment new]; attachment.image = image; attachment.bounds = CGRectMake(0, offsetY, attachment.image.size.width, attachment.image.size.height); 

不需要子类

你应该使用字体的capHeight。

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]; 

迅速

 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) 

附件图像呈现在文本的基线上。 它的y轴与核心graphics坐标系相反。 如果要向上移动图像,请将bounds.origin.y设置为正值。

图像应该与文本的capHeight垂直alignment。 所以我们需要将bounds.origin.y设置为(capHeight - imageHeight)/2

避免图像上的锯齿效应,我们应该围绕y的小数部分。 但字体和图像通常很小,甚至1px的差异使得图像看起来像错位。 所以我在分割之前应用了圆的函数。 它使得y值的小数部分为.0或.5

在你的情况下,图像高度大于字体的capHeight。 但是你可以用同样的方法。 偏移量y值将是负值。 它将从基线以下进行布局。

在这里输入图像说明

@Travis是正确的,偏移量是字体下降。 如果您还需要缩放图像,则需要使用NSTextAttachment的子类。 下面是代码,这是从这篇文章的启发。 我也把它作为一个要点 。

 import UIKit class ImageAttachment: NSTextAttachment { var verticalOffset: CGFloat = 0.0 // To vertically center the image, pass in the font descender as the vertical offset. // We cannot get this info from the text container since it is sometimes nil when `attachmentBoundsForTextContainer` // is called. convenience init(_ image: UIImage, verticalOffset: CGFloat = 0.0) { self.init() self.image = image self.verticalOffset = verticalOffset } override func attachmentBoundsForTextContainer(textContainer: NSTextContainer, proposedLineFragment lineFrag: CGRect, glyphPosition position: CGPoint, characterIndex charIndex: Int) -> CGRect { let height = lineFrag.size.height var scale: CGFloat = 1.0; let imageSize = image!.size if (height < imageSize.height) { scale = height / imageSize.height } return CGRect(x: 0, y: verticalOffset, width: imageSize.width * scale, height: imageSize.height * scale) } } 

使用方法如下:

 var text = NSMutableAttributedString(string: "My Text") let image = UIImage(named: "my-image")! let imageAttachment = ImageAttachment(image, verticalOffset: myLabel.font.descender) text.appendAttributedString(NSAttributedString(attachment: imageAttachment)) myLabel.attributedText = text 

如果你有一个非常大的上升,并想中心像我这样的图像(帽高的中心)尝试这个

 let attachment: NSTextAttachment = NSTextAttachment() attachment.image = image if let image = attachment.image{ let y = -(font.ascender-font.capHeight/2-image.size.height/2) attachment.bounds = CGRect(x: 0, y: y, width: image.size.width, height: image.size.height).integral } 

y的计算如下图所示

在这里输入图像说明

请注意,y值是0,因为我们希望图像从原点向下移动

如果你想要它在整个标签的中间。使用这个y值:

 let y = -((font.ascender-font.descender)/2-image.size.height/2) 

我有一个类的类与UIImage的NSString和反之亦然。

https://github.com/Pradeepkn/TextWithImage

请享用。

请使用-lineFrag.size.height / 5.0作为边界高度。 这正是图像的中心,并与所有字体大小的文本alignment

 override func attachmentBoundsForTextContainer(textContainer: NSTextContainer, proposedLineFragment lineFrag: CGRect, glyphPosition position: CGPoint, characterIndex charIndex: Int) -> CGRect { var bounds:CGRect = CGRectZero bounds.size = self.image?.size as CGSize! bounds.origin = CGPointMake(0, -lineFrag.size.height/5.0); return bounds; }