Frage

Ich arbeite an einem CatextLayer, den ich sowohl in Mac als auch in iOS verwenden möchte. Kann ich die vertikale Ausrichtung des Textes innerhalb der Ebene steuern?

In diesem speziellen Fall möchte ich es vertikal zentrieren - aber Informationen über andere vertikale Ausrichtungen wären auch von Interesse.

EDIT: Ich habe gefunden Dies, aber ich kann es nicht zum Laufen bringen.

War es hilfreich?

Lösung 13

Wie ich am besten beurteilen kann, lautet die Antwort auf meine Frage "Nein."

Andere Tipps

Die richtige Antwort ist, wie Sie bereits gefunden haben, die richtige Antwort hier in objektiv-c und arbeitet für iOS. Es funktioniert, indem es die Unterkrassung der CATextLayer und überschreiben die drawInContext Funktion.

Jedoch, Ich habe einige Verbesserungen am Code vorgenommen, Wie unten gezeigt, verwenden Sie den Code von David Hoerl als Grundlage. Das Änderungen Komm ausschließlich in Die vertikale Position des Textes neu berechnen dargestellt durch die yDiff. Ich habe es mit meinem eigenen Code getestet.

Hier ist der Code für Swift -Benutzer:

class LCTextLayer : CATextLayer {

    // REF: http://lists.apple.com/archives/quartz-dev/2008/Aug/msg00016.html
    // CREDIT: David Hoerl - https://github.com/dhoerl 
    // USAGE: To fix the vertical alignment issue that currently exists within the CATextLayer class. Change made to the yDiff calculation.

    override func draw(in context: CGContext) {
        let height = self.bounds.size.height
        let fontSize = self.fontSize
        let yDiff = (height-fontSize)/2 - fontSize/10

        context.saveGState()
        context.translateBy(x: 0, y: yDiff) // Use -yDiff when in non-flipped coordinates (like macOS's default)
        super.draw(in: context)
        context.restoreGState()
    }
}

Vielleicht zu spät zur Antwort, aber Sie können die Textgröße berechnen und dann die Position des Textlayers festlegen. Außerdem müssen Sie den Textalaligment -Modus "Mitte" den Textalaligment -Modus einsetzen.

CGRect labelRect = [text boundingRectWithSize:view.bounds.size options:NSStringDrawingUsesLineFragmentOrigin attributes:@{ NSFontAttributeName : [UIFont fontWithName:@"HelveticaNeue" size:17.0] } context:nil];
CATextLayer *textLayer = [CATextLayer layer];
[textLayer setString:text];
[textLayer setForegroundColor:[UIColor redColor].CGColor];
[textLayer setFrame:labelRect];
[textLayer setFont:CFBridgingRetain([UIFont fontWithName:@"HelveticaNeue" size:17.0].fontName)];
[textLayer setAlignmentMode:kCAAlignmentCenter];
[textLayer setFontSize:17.0];
textLayer.masksToBounds = YES;
textLayer.position = CGPointMake(CGRectGetMidX(view.bounds), CGRectGetMidY(view.bounds));
[view.layer addSublayer:textLayer];

Es ist eine verspätete Antwort, aber ich habe heutzutage die gleiche Frage und habe das Problem mit der folgenden Untersuchung gelöst.

Die vertikale Ausrichtung hängt von dem Text ab, den Sie zeichnen müssen, und von der Schriftart, die Sie verwenden. Daher gibt es keine Möglichkeit, sie für alle Fälle vertikal zu machen.

Wir können jedoch den vertikalen Mittelpunkt für verschiedene Fälle trotzdem berechnen.

Laut Apple's Über Texthandhabung in iOS, Wir müssen wissen, wie der Text gezeichnet wird.

Zum Beispiel versuche ich, vertikale Saiten an Wochentagen ausgerichtet zu werden: Sonne, Mon, Di, ....

Für diesen Fall hängt die Höhe des Textes davon ab Kappenhöhe, und es gibt keine Abstammung Für diese Charaktere. Wenn wir diesen Text also mit der Mitte ausrichten müssen, können wir den Versatz der Oberseite des CAP -Charakters berechnen, z. B. die Position der Spitze des Charakters "S".

Nach der folgenden Abbildung:

fig

Der obere Raum für den Kapitalcharakter "S" wäre

font.ascender - font.capHeight

Und der untere Platz für den Kapitalcharakter "S" wäre

font.descender + font.leading

Also müssen wir uns ein bisschen von oben bewegen.

y = (font.ascender - font.capHeight + font.descender + font.leading + font.capHeight) / 2

Das entspricht:

y = (font.ascender + font.descender + font.leading) / 2

Dann kann ich den Text vertikal ausrichten.

Fazit:

  1. Wenn Ihr Text kein Zeichen enthält, überschreiten Sie die Basislinie, z. "P", "J", "G" und keinen Charakter über der Oberseite der Kappenhöhe, z. "F". Sie können die obige Formel verwenden, um den Text vertikal auszurichten.

    y = (font.ascender + font.descender + font.leading) / 2
    
  2. Wenn Ihr Text Zeichen unterhalb der Basislinie enthält, z. "P", "J" und kein Zeichen überschreiten die Oberseite der Kappenhöhe, z. "F". Dann wäre die vertikale Formel:

    y = (font.ascender + font.descender) / 2
    
  3. Wenn Ihr Text nicht unter der Basislinie, z. "J", "P", enthält, enthält und enthält Zeichen, die über der Kappenhöhenlinie gezeichnet sind, z. "F". Dann wäre y:

    y = (font.descender + font.leading) / 2
    
  4. Wenn in Ihrem Text alle Zeichen auftreten würden, ist Y gleich:

    y = font.leading / 2
    

Swift 3 -Version für reguläre und zugeschriebene Zeichenfolgen.

class ECATextLayer: CATextLayer {
    override open func draw(in ctx: CGContext) {
        let yDiff: CGFloat
        let fontSize: CGFloat
        let height = self.bounds.height

        if let attributedString = self.string as? NSAttributedString {
            fontSize = attributedString.size().height
            yDiff = (height-fontSize)/2
        } else {
            fontSize = self.fontSize
            yDiff = (height-fontSize)/2 - fontSize/10
        }

        ctx.saveGState()
        ctx.translateBy(x: 0.0, y: yDiff)
        super.draw(in: ctx)
        ctx.restoreGState()
    }
}

Danke @iamktothed, es funktioniert. Im Folgenden finden Sie Swift 3 -Version:

class CXETextLayer : CATextLayer {

override init() {
    super.init()
}

override init(layer: Any) {
    super.init(layer: layer)
}

required init(coder aDecoder: NSCoder) {
    super.init(layer: aDecoder)
}

override func draw(in ctx: CGContext) {
    let height = self.bounds.size.height
    let fontSize = self.fontSize
    let yDiff = (height-fontSize)/2 - fontSize/10

    ctx.saveGState()
    ctx.translateBy(x: 0.0, y: yDiff)
    super.draw(in: ctx)
    ctx.restoreGState()
}
}

Der Code von GBK funktioniert. Unten finden Sie den Code von GBK, der für Xcode 8 Beta 6 aktualisiert wurde

Schritt 1. Unterklasse CatextLayer. In dem folgenden Code habe ich die Unterklasse "mycatextLayer" außerhalb Ihrer Ansichts -Controller -Klasse Kopieren/Einfügen des folgenden Codes benannt.

class MyCATextLayer: CATextLayer {

// REF: http://lists.apple.com/archives/quartz-dev/2008/Aug/msg00016.html
// CREDIT: David Hoerl - https://github.com/dhoerl
// USAGE: To fix the vertical alignment issue that currently exists within the CATextLayer class. Change made to the yDiff calculation.

override init() {
    super.init()
}

required init(coder aDecoder: NSCoder) {
    super.init(layer: aDecoder)
}

override func draw(in ctx: CGContext) {
    let height = self.bounds.size.height
    let fontSize = self.fontSize
    let yDiff = (height-fontSize)/2 - fontSize/10

    ctx.saveGState()
    ctx.translateBy(x: 0.0, y: yDiff)
    super.draw(in: ctx)
    ctx.restoreGState()
   }
}

Schritt 2. Erstellen Sie in Ihrer Ansichts -Controller -Klasse in Ihrer ".Swift" -Datei Ihr CatextLabel. Im Codebeispiel habe ich die Unterklasse "mydopecatextLayer" bezeichnet.

let MyDopeCATextLayer: MyCATextLayer = MyCATextLayer()

Schritt 3. Stellen Sie Ihren neuen CatextLayer mit gewünschten Text/Farbe/Grenzen/Frame ein.

MyDopeCATextLayer.string = "Hello World"    // displayed text
MyDopeCATextLayer.foregroundColor = UIColor.purple.cgColor //color of text is purple
MyDopeCATextLayer.frame = CGRect(x: 0, y:0, width: self.frame.width, height: self.frame.height)  
MyDopeCATextLayer.font = UIFont(name: "HelveticaNeue-UltraLight", size: 5) //5 is ignored, set actual font size using  ".fontSize" (below)
MyDopeCATextLayer.fontSize = 24
MyDopeCATextLayer.alignmentMode = kCAAlignmentCenter //Horizontally centers text.  text is automatically centered vertically because it's set in subclass code
MyDopeCATextLayer.contentsScale = UIScreen.main.scale  //sets "resolution" to whatever the device is using (prevents fuzzyness/blurryness)

Schritt 4. fertig

Der Code für Swift 3 basiert auf Code @iamktothed

Wenn Sie eine zugeschriebene Zeichenfolge für die Einstellung von Schriftstellungseigenschaften verwenden, können Sie die Funktionsgröße () von NsattributString verwenden, um die Höhe der Zeichenfolge zu berechnen. Ich denke, dieser Code behebt auch die von @enix beschriebenen Probleme

class LCTextLayer: CATextLayer {

    override init() {
        super.init()
    }

    override init(layer: Any) {
        super.init(layer: layer)
    }

    required init(coder aDecoder: NSCoder) {
        super.init(layer: aDecoder)
    }

    override open func draw(in ctx: CGContext) {

        if let attributedString = self.string as? NSAttributedString {

            let height = self.bounds.size.height
            let stringSize = attributedString.size()
            let yDiff = (height - stringSize.height) / 2

            ctx.saveGState()
            ctx.translateBy(x: 0.0, y: yDiff)
            super.draw(in: ctx)
            ctx.restoreGState()
        }
    }
}

Es gibt also keine "direkte" Möglichkeit, dies zu tun, aber Sie können dasselbe mit Textmetriken erreichen:

http://developer.apple.com/library/ios/#documentation/uikit/reference/nsstring_uikit_additions/reference/reference.html

... Finden Sie beispielsweise die Größe des Textes und verwenden Sie diese Informationen, um sie in der übergeordneten Ebene zu platzieren. Hoffe das hilft.

Sie müssen wissen, wo CatextLayer die Grundlinie Ihres Textes einfügt. Sobald Sie wissen, dass das Koordinatensystem innerhalb der Ebene ausgleichen, passen Sie bounds.Origin.y durch den Unterschied zwischen der Grundlage der Basislinie und dem Ort an, an dem sie sich befinden, angesichts der Metriken der Schriftart.

CatextLayer ist eine kleine schwarze Box und es ist etwas schwierig, meine Basislinie zu sitzen - siehe meine Antwort hier für iOS - Ich habe keine Ahnung, was das Verhalten auf Mac ist.

Ich modifizierte leicht Diese Antwort von @iamkothed. Die Unterschiede sind:

  • Die Berechnung der Texthöhe basiert auf NSString.size(with: Attributes). Ich weiß nicht, ob es eine Verbesserung gegenüber ist (height-fontSize)/2 - fontSize/10, aber ich denke gerne, dass es so ist. Obwohl meiner Erfahrung nach, NSString.size(with: Attributes) Gibt nicht immer die am besten geeignete Größe zurück.
  • hinzugefügt invertedYAxis Eigentum. Es war nützlich, um dies zu exportieren CATextLayer Unterklasse Verwenden AVVideoCompositionCoreAnimationTool. AvFoundation arbeitet in der "normalen" Y -Achse, und deshalb musste ich diese Eigenschaft hinzufügen.
  • Funktioniert nur mit NSString. Sie können Swifts verwenden String Klasse jedoch, weil es automatisch an übergeht NSString.
  • Es ignoriert CATextLayer.fontSize Eigentum und sich vollständig auf CATextLayer.font Eigentum, das ein sein muss UIFont Beispiel.

    class VerticallyCenteredTextLayer: CATextLayer {
        var invertedYAxis: Bool = true
    
        override func draw(in ctx: CGContext) {
            guard let text = string as? NSString, let font = self.font as? UIFont else {
                super.draw(in: ctx)
                return
            }
    
            let attributes = [NSAttributedString.Key.font: font]
            let textSize = text.size(withAttributes: attributes)
            var yDiff = (bounds.height - textSize.height) / 2
            if !invertedYAxis {
                yDiff = -yDiff
            }
            ctx.saveGState()
            ctx.translateBy(x: 0.0, y: yDiff)
            super.draw(in: ctx)
            ctx.restoreGState()
        }
    }
    

Ich möchte eine Lösung vorschlagen, die Multiline -Wickeln in die verfügbare Box berücksichtigt:

final class CACenteredTextLayer: CATextLayer {
    override func draw(in ctx: CGContext) {
        guard let attributedString = string as? NSAttributedString else { return }

        let height = self.bounds.size.height
        let boundingRect: CGRect = attributedString.boundingRect(
            with: CGSize(width: bounds.width,
                         height: CGFloat.greatestFiniteMagnitude),
            options: NSStringDrawingOptions.usesLineFragmentOrigin,
            context: nil)
        let yDiff: CGFloat = (height - boundingRect.size.height) / 2

        ctx.saveGState()
        ctx.translateBy(x: 0.0, y: yDiff)
        super.draw(in: ctx)
        ctx.restoreGState()
    }
}

Es hinen nichts, dass Sie eine Calayer -Hierarchie mit einem generischen Calayer (Container) erstellen, der den CatextLayer als Untermesser hat.

Anstatt Schriftgrößen für den CatextLayer zu berechnen, berechnen Sie einfach den Versatz des CatextLayer im Calayer, damit er vertikal zentriert ist. Wenn Sie den Ausrichtungsmodus der Textebene auf zentriert einstellen und die Breite der Textebene mit dem umschließenden Behälter genauso gestalten, zentriert sie sich auch horizontal.

let container = CALayer()
let textLayer = CATextLayer()

// create the layer hierarchy
view.layer.addSublayer(container)
container.addSublayer(textLayer)

// Setup the frame for your container
...


// Calculate the offset of the text layer so that it is centred
let hOffset = (container.frame.size.height - textLayer.frame.size.height) * 0.5

textLayer.frame = CGRect(x:0.0, y: hOffset, width: ..., height: ...)

Der Unterschichtrahmen ist relativ zu seinem Elternteil, daher ist die Berechnung ziemlich einfach. An dieser Stelle keine Notwendigkeit, sich um die Schriftgrößen zu kümmern. Dies wird von Ihrem Code bearbeitet, der sich mit dem CatextLayer befasst, nicht im Layoutcode.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top