在单行UILabel旁边显示NSTextAttachment图像

Sea*_*ser 106 objective-c uilabel nstextattachment ios swift

我想将NSTextAttachment图像附加到我的属性字符串并使其垂直居中.

我使用以下代码来创建我的字符串

        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];
Run Code Online (Sandbox Code Playgroud)

但是,图像看起来与单元格textLabel的顶部对齐.

在此输入图像描述

如何更改绘制附件的矩形?

MG *_*Han 156

您可以使用字体的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];
Run Code Online (Sandbox Code Playgroud)

迅速

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)
Run Code Online (Sandbox Code Playgroud)

附件图像呈现在文本的基线上.并且它的y轴像核心图形坐标系一样被反转.如果要向上移动图像,请将其设置bounds.origin.y为正数.

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

避免对图像产生锯齿状的影响,我们应该围绕y的小数部分.但是字体和图像通常很小,即使1px的差异也会使图像看起来像是不对齐的.所以我在分割前应用了圆函数.它使y值的分数部分为.0或.5

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

在此输入图像描述

  • 光是插图就值得+1!感谢分享。 (2认同)

Tra*_*vis 103

试试- [NSTextAttachment bounds].不需要子类化.

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

  • 对于Swift 3.0:```attachment.bounds = CGRect(x:0.0,y:self.font.descender,width:attachment.image!.size.width,height:attachment.image!.size.height)``` (11认同)

bor*_*ero 59

我发现了一个完美的解决方案,对我来说就像一个魅力,但是你必须自己尝试(可能常数取决于设备的分辨率,也许是其他的;)

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
}
Run Code Online (Sandbox Code Playgroud)

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

  • 这是我用于y计算的内容:下降器+(abs(下降器)+ capHeight)/ 2 - iconHeight/2 (2认同)

rob*_*off 57

您可以通过子类化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;
}
Run Code Online (Sandbox Code Playgroud)

这不是一个完美的解决方案.您必须"通过眼睛"找出Y原点,如果您更改字体或图标大小,您可能想要更改Y原点.但我无法找到更好的方法,除非将图标放在单独的图像视图中(这有其自身的缺点).

  • 特拉维斯的答案是一个没有子类化的更清洁的解决方案. (4认同)
  • 不知道为什么他们对此投下了反对票,这对我有帮助+1 (2认同)

Jak*_*lář 34

关于什么:

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);
Run Code Online (Sandbox Code Playgroud)

不需要子类化

  • 比使用self.font.descender(在运行iOS 8的iPhone 4s模拟器上的默认值为~4)更好.-10看起来更像是默认字体样式/大小的近似值. (2认同)

pha*_*ann 10

@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)
    }
}
Run Code Online (Sandbox Code Playgroud)

使用方法如下:

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
Run Code Online (Sandbox Code Playgroud)


Ind*_*yZa 9

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

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
}
Run Code Online (Sandbox Code Playgroud)

y计算如下图所示

在此输入图像描述

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

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

let y = -((font.ascender-font.descender)/2-image.size.height/2)
Run Code Online (Sandbox Code Playgroud)


Osc*_*car 5

我们可以在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
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以拨打电话发送图片名称和字体:

let imageAttachment = NSTextAttachment.getCenteredImageAttachment(with: imageName,
                                                                   and: youLabel?.font)
Run Code Online (Sandbox Code Playgroud)

然后将imageAttachment附加到attributedString