Frage Zentrieren Sie das Bild NSTextAttachment neben der Einzelzeile UILabel


Ich möchte ein NSTextAttachment-Bild an meine attributierte Zeichenfolge anhängen und vertikal zentrieren lassen.

Ich habe den folgenden Code verwendet, um meine Zeichenfolge zu erstellen

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

Das Bild scheint jedoch am oberen Rand der Zelle textLabel ausgerichtet zu sein.

enter image description here

Wie kann ich das Rechteck ändern, in dem der Anhang gezeichnet wird?


74
2017-09-29 17:47


Ursprung


Antworten:


Sie können das Rect durch Unterklassen ändern NSTextAttachment und überschreiben attachmentBoundsForTextContainer:proposedLineFragment:glyphPosition:characterIndex:. Beispiel:

- (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;
}

Es ist keine perfekte Lösung. Sie müssen den Y-Ursprung "nach Augenmaß" herausfinden und wenn Sie die Schriftart oder die Symbolgröße ändern, möchten Sie wahrscheinlich den Y-Ursprung ändern. Aber ich konnte keinen besseren Weg finden, als das Symbol in eine separate Bildansicht zu stellen (was seine eigenen Nachteile hat).


40
2017-09-29 19:32



Versuchen - [NSTextAttachment bounds]. Keine Unterklassen erforderlich.

Für den Kontext rendere ich ein UILabel Für die Verwendung als Anhangsbild legen Sie die Grenzen wie folgt fest: attachment.bounds = CGRectMake(0, self.font.descender, attachment.image.size.width, attachment.image.size.height) und Grundlinien von Text innerhalb des Beschriftungsbildes und Text in der attributierten Zeichenkette, wie gewünscht.


84
2018-02-05 22:22



Sie können die capHeight der Schriftart verwenden.

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

Schnell

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)

Das Anhangsbild wird auf der Grundlinie des Textes gerendert. Und die y-Achse ist umgekehrt wie das Grafikkoordinatensystem. Wenn Sie das Bild nach oben verschieben möchten, stellen Sie die Option ein bounds.origin.y zu positiv.

Das Bild sollte vertikal mit der capHeight des Textes ausgerichtet werden. Also müssen wir das einstellen bounds.origin.y zu (capHeight - imageHeight)/2.

Um einen gezackten Effekt auf das Bild zu vermeiden, sollten wir den Bruchteil des y runden. Aber Schriftarten und Bilder sind in der Regel klein, sogar 1px Unterschied macht das Bild wie falsch ausgerichtet aussieht. Also habe ich die Rundenfunktion vor dem Teilen angewendet. Es macht den Bruchteil des y-Wertes zu .0 oder .5

In Ihrem Fall ist die Bildhöhe größer als die capHeight der Schrift. Aber Sie können den gleichen Weg benutzen. Der Offset-Y-Wert ist negativ. Und es wird von unten der Basislinie ausgelegt.

enter image description here


67
2017-07-18 08:12



Ich habe dafür eine perfekte Lösung gefunden, funktioniert aber wie ein Zauber für mich, allerdings muss man es selbst ausprobieren (wahrscheinlich hängt die Konstante von der Auflösung des Gerätes und vielleicht auch was auch immer ab;)

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
}

Sollte arbeiten und sollte nicht in irgendeiner Weise verschwommen sein (dank CGRectIntegral)


56
2017-12-01 18:17



Wie wäre es mit:

CGFloat offsetY = -10.0;

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

Keine Unterklassen erforderlich


31
2018-04-29 21:11



@ Travis ist korrekt, dass der Offset der Font-Descender ist. Wenn Sie das Bild auch skalieren müssen, müssen Sie eine Unterklasse von NSTextAttachment verwenden. Unten ist der Code, der von inspiriert wurde Dieser Artikel. Ich habe es auch als Kern.

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)
    }
}

Verwenden Sie wie folgt:

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

9
2018-03-22 22:33



Wenn Sie eine sehr große Aszendent haben und das Bild (Mitte der Kappenhöhe) wie ich zentrieren wollen, versuchen Sie dies

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
}

Die y-Berechnung ist wie das Bild unten

enter image description here

Beachten Sie, dass der y-Wert 0 ist, weil das Bild vom Ursprung nach unten verschoben werden soll

Wenn Sie möchten, dass es sich in der Mitte des gesamten Labels befindet. Verwenden Sie diesen y-Wert:

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

5
2018-04-03 19:10



Wir können in swift 4 eine Erweiterung erstellen, die einen Anhang mit einem zentrierten Bild wie diesem erzeugt:

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
    }
}

Dann können Sie den Anruf tätigen, indem Sie den Namen des Bildes und die Schriftart senden:

let imageAttachment = NSTextAttachment.getCenteredImageAttachment(with: imageName,
                                                                   and: youLabel?.font)

Fügen Sie dann imageAttachment an attributedString an


1
2018-01-17 12:28



Verwenden Sie -lineFrag.size.height / 5.0 für die Begrenzungshöhe. Dadurch wird das Bild genau zentriert und mit Text für die gesamte Schriftgröße ausgerichtet

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

0
2018-03-16 05:40