ios 单行 UILabel 旁边的中心 NSTextAttachment 图像
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/26105803/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Center NSTextAttachment image next to single line UILabel
提问by Sean Danzeiser
I'd like to append an NSTextAttachment
image to my attributed string and have it centered vertically.
我想将NSTextAttachment
图像附加到我的属性字符串并使其垂直居中。
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
.
但是,图像似乎与单元格的顶部对齐textLabel
。
How can I change the rect in which the attachment is drawn?
如何更改绘制附件的矩形?
采纳答案by rob mayoff
You can change the rect by subclassing NSTextAttachment
and overriding attachmentBoundsForTextContainer:proposedLineFragment:glyphPosition:characterIndex:
. Example:
您可以通过子类化NSTextAttachment
和覆盖来更改 rect 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;
}
It's not a perfect solution. You have to figure out the Y-origin “by eye” and if you change the font or the icon size, you'll probably want to change the Y-origin. But I couldn't find a better way, except by putting the icon in a separate image view (which has its own disadvantages).
这不是一个完美的解决方案。您必须“通过眼睛”找出 Y 原点,如果您更改字体或图标大小,您可能想要更改 Y 原点。但是我找不到更好的方法,除了将图标放在单独的图像视图中(这有其自身的缺点)。
回答by MG Han
You can use the capHeight of the font.
您可以使用字体的 capHeight。
Objective-C
目标-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.
附件图像呈现在文本的基线上。并且它的 y 轴像核心图形坐标系一样反转。如果要向上移动图像,请将 设置bounds.origin.y
为正。
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
.
图像应与文本的 capHeight 垂直居中对齐。所以我们需要设置bounds.origin.y
为(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
避免对图像产生一些锯齿效果,我们应该四舍五入 y 的小数部分。但是字体和图像通常很小,即使是 1px 的差异也会使图像看起来没有对齐。所以我在划分之前应用了round函数。它使 y 值的小数部分变为 .0 或 0.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.
在您的情况下,图像高度大于字体的 capHeight。但是你可以用同样的方法。偏移 y 值将为负。它将从基线的下方布置。
回答by Travis
Try - [NSTextAttachment bounds]
. No subclassing required.
试试- [NSTextAttachment bounds]
。不需要子类化。
For context, I am rendering a UILabel
for use as the attachment image, then setting the bounds like so:
attachment.bounds = CGRectMake(0, self.font.descender, attachment.image.size.width, attachment.image.size.height)
and baselines of text within label image and text in attributed string line up as desired.
对于上下文,我渲染一个UILabel
用作附件图像,然后像这样设置边界:
attachment.bounds = CGRectMake(0, self.font.descender, attachment.image.size.width, attachment.image.size.height)
标签图像中的文本基线和属性字符串中的文本根据需要排列。
回答by borchero
I found a perfect solution to this, works like a charm for me though, however you have to try it out yourself (probably the constant depends on the resolution of the device and maybe whatever ;)
我找到了一个完美的解决方案,虽然对我来说就像一个魅力,但是你必须自己尝试一下(可能常数取决于设备的分辨率,也许其他什么;)
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
}
Should work and shouldn't be blurry in any way (thanks to CGRectIntegral
)
应该工作并且不应该以任何方式模糊(感谢CGRectIntegral
)
回答by Jakub Truhlá?
What about:
关于什么:
CGFloat offsetY = -10.0;
NSTextAttachment *attachment = [NSTextAttachment new];
attachment.image = image;
attachment.bounds = CGRectMake(0.0,
offsetY,
attachment.image.size.width,
attachment.image.size.height);
No subclassing needed
不需要子类化
回答by phatmann
@Travis is correct that the offset is the font descender. If you also need to scale the image, you will need to use a subclass of NSTextAttachment. Below is the code, which was inspired by this article. I also posted it as a gist.
@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)
}
}
Use as follows:
使用方法如下:
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
回答by IndyZa
If you have a very large ascendent and want to center the image (center of the cap height) like me try this
如果你有一个非常大的上升点并且想要像我一样将图像居中(大写高度的中心)试试这个
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
}
The y calculation is as the picture below
y计算如下图
Note that the y value is 0 because we want the image to shift down from the origin
请注意,y 值为 0,因为我们希望图像从原点向下移动
If you want it to be in the middle of the whole label.Use this y value:
如果你想让它在整个标签的中间。使用这个 y 值:
let y = -((font.ascender-font.descender)/2-image.size.height/2)
回答by Oscar
We can make an extension in swift 4 that generates an attachment with a centered image like this one:
我们可以在 swift 4 中进行扩展,以生成带有居中图像的附件,如下所示:
extension NSTextAttachment {
static func getCenteredImageAttachment(with imageName: String, and
font: UIFont?) -> NSTextAttachment? {
let imageAttachment = NSTextAttachment()
guard let image = UIImage(named: imageName),
let font = font else { return nil }
imageAttachment.bounds = CGRect(x: 0, y: (font.capHeight - image.size.height).rounded() / 2, width: image.size.width, height: image.size.height)
imageAttachment.image = image
return imageAttachment
}
}
Then you can make the call sending the name of the image and the font:
然后你可以打电话发送图像的名称和字体:
let imageAttachment = NSTextAttachment.getCenteredImageAttachment(with: imageName,
and: youLabel?.font)
And then append the imageAttachment to the attributedString
然后将 imageAttachment 附加到 attributesString
回答by Reimond Hill
In my case calling sizeToFit() helped. In swift 5.1
在我的情况下,调用 sizeToFit() 有帮助。在快速 5.1
Inside your custom label:
在您的自定义标签内:
func updateUI(text: String?) {
guard let text = text else {
attributedText = nil
return
}
let attributedString = NSMutableAttributedString(string:"")
let textAttachment = NSTextAttachment ()
textAttachment.image = image
let sizeSide: CGFloat = 8
let iconsSize = CGRect(x: CGFloat(0),
y: (font.capHeight - sizeSide) / 2,
width: sizeSide,
height: sizeSide)
textAttachment.bounds = iconsSize
attributedString.append(NSAttributedString(attachment: textAttachment))
attributedString.append(NSMutableAttributedString(string: text))
attributedText = attributedString
sizeToFit()
}
回答by Harish Kumar Kailas
Please use -lineFrag.size.height/5.0 for the bounds height. This exactly centres the image and aligned with text for all the size of fonts
请使用 -lineFrag.size.height/5.0 作为边界高度。这恰好使图像居中并与所有字体大小的文本对齐
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;
}