SpriteKit:有没有一种方法可以根据SKLabelNode的基线将其居中?

3
一个标签有四种不同的verticalAlignmentMode.Baseline.Bottom.Center.Top
我希望该标签根据其基线在其位置上居中。使用.Center对我来说行不通,因为框架底部不是文本的基线,而是最低字母(例如像'y'这样的字母)的底部。
我还尝试使用.Baseline并从y位置减去框架高度的一半,但这也行不通,并导致与.Center相同的问题。
我尝试要居中的标签中的文本为"Play!"。将模式设置为'.Center'会使文本比我想要的位置略高,这很明显。将文本更改为"Pla!"可以解决问题,因为'y'被删除,没有字符悬挂在基线以下(但我显然不能以此作为解决方案)。
我想寻求一个解决此问题的建议-也许有一种方法可以得到基线的位置?谢谢!

基线将放置在该位置。您需要计算出从节点顶部到基线的大小,然后减去那个数量的一半以使其居中。 - Knight0fDragon
1
最快的解决方案是创建一个临时标签,不包含任何低于基线的字体字符,并使用该框架高度的一半。 - Knight0fDragon
谢谢 - 我想这是一个快速的“hack”,可以让我完成它。不过,我仍然在想是否有一种更“简洁”的方法 :) - Shuri2060
没有简单的方法,您需要编写一个扩展程序,通过使用UIFont的“ascender”(基线上方)和“descender”(基线下方)属性来获取基线位置。 - Knight0fDragon
1个回答

0

我曾经遇到过同样的问题,通过这个问题和答案的帮助,我找到了一个不错的解决方案。

我想要将标签节点的文本与自定义按钮节点(一个包含形状节点的标签节点,用于绘制轮廓)对齐。

我还想要将开关(打开/关闭)按钮与标签节点的基线对齐,并使用标签中文本的xHeight相同的高度。

Aligning labels, buttons and shapes 红线显示所有标签和按钮都正确对齐。

因此,为了实现这一点,我做了以下几步。

我创建了一个Font类,可以从SKLabelNode中的fontNamefontSize创建字体对象。

在内部,它将创建一个 NSFont(macOS)或 UIFont(iOS)。并设置上升和下降属性。为了方便起见,还有一个getter返回字体的最大可能高度。

import Foundation

#if os(macOS)
import Cocoa
#endif

#if os(iOS)
import UIKit
#endif

enum FontError: LocalizedError {
    case invalidFont(String, CGFloat)

    var errorDescription: String? {
        switch self {
        case .invalidFont(let name, let size):
            return "Could not create font with name \(name) and size: \(size)"
        }
    }
}

class Font {
    private(set) var name: String
    private(set) var size: CGFloat

    private(set) var ascender: CGFloat
    private(set) var descender: CGFloat
    private(set) var xHeight: CGFloat

    var maxHeight: CGFloat {
        return self.ascender + fabs(self.descender)
    }

    init(name: String, size: CGFloat) throws {
        // check if font can be created, otherwise crash
        // set ascender, descender, etc...
        #if os(macOS)
        guard let font = NSFont(name: name, size: size) else {
            throw FontError.invalidFont(name, size)
        }

        self.ascender = font.ascender
        self.descender = font.descender
        self.xHeight = font.xHeight
        #endif

        #if os(iOS)
        guard let font = UIFont(name: name, size: size) else {
            throw FontError.invalidFont(name, size)
        }
        self.ascender = font.ascender
        self.descender = font.descender
        self.xHeight = font.xHeight
        #endif

        self.name = name
        self.size = size
    }
}

然后我在我的标签位置计算中使用maxHeight。例如,在我的自定义ButtonNode(一个包含SKLabelNodeSKShapeNode)中,我执行以下操作(简化):

// in the constructor of my custom 
// button node ...
let height = 30

self.label = SKLabelNode(text: "Back")
// in order to position properly, set 
// vertical alignment to baseline
self.label.verticalAlignmentMode = .baseline

let font = try Font(name: self.label.fontName!, size: self.label.fontSize)
// depending on the font you might want to add 
// an additional y offset to place labels 
// higher or lower within the node
let yOffset = (height - font.maxHeight) / 2)
let labelWidth = self.label.calculateAccumulatedFrame().width

let labelFrame = CGRect(
    x: 0,
    y: 0,
    width: labelWidth,
    height: height
)

self.path = CGPath(roundedRect: labelFrame, cornerWidth: 5, cornerHeight: 5, transform: nil)

self.label.position = CGPoint(x: labelFrame.width / 2, y: yOffset)

附言: 如果您不想创建一个单独的Font类,但仍希望代码在iOS和macOS上正常工作,您可以为NSFontUIFont创建一个类型别名。由于您可以使用相同的构造函数,因此只需要添加一个扩展来计算字体的最大高度(ascender + abs(descender))。

我更喜欢创建一个类,这样如果无法正确创建字体,我就可以抛出错误。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接