swift 2 sprite-kit 中的多行标签?

Posted

技术标签:

【中文标题】swift 2 sprite-kit 中的多行标签?【英文标题】:Multi-line label in swift 2 sprite-kit? 【发布时间】:2016-02-01 00:51:06 【问题描述】:

我需要能够在 swift 2 sprite-kit 中为游戏制作多行标签。文本需要环绕而不是离开屏幕。贝娄是我所拥有的,但我不知道该怎么做

import Foundation
import UIKit
import SpriteKit

class JDQuotes: SKLabelNode 

    var number = 0

    init(num: Int) 
        super.init()

        if num == 1  

            text = "\"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. laborum.\""

        
    

    required init?(coder aDecoder: NSCoder) 
        fatalError("init(coder:) has not been implemented")
    

【问题讨论】:

我只需要一个 UIlabel 并作为子视图添加到 SKView 之上。 这里是第三方解决方案。 SKLabel 通常不支持多行。 https://craiggrummitt.wordpress.com/2015/04/10/multi-line-sklabels-in-swift/ 【参考方案1】:

ios 11 开始,这终于可以通过 SKLabelNode 实现了:

    let lb = SKLabelNode(fontNamed: "Copperplate")
    lb.text = "Put your long text here..."
    lb.numberOfLines = 0
    lb.preferredMaxLayoutWidth = 1000

【讨论】:

请注意,numberOfLinespreferredMaxLayoutWidth 等较新的方法仅适用于 iOS 11.0 或更高版本。所以如果你想支持旧版本,你将不得不放弃这些方法。【参考方案2】:

here 上有一个 Github 解决方案,因为 SKLabelNodes 不支持多行。

引用代码:

import SpriteKit

class SKMultilineLabel: SKNode 
//props
var labelWidth:Int didSet update()
var labelHeight:Int = 0
var text:String didSet update()
var fontName:String didSet update()
var fontSize:CGFloat didSet update()
var pos:CGPoint didSet update()
var fontColor:UIColor didSet update()
var leading:Int didSet update()
var alignment:SKLabelHorizontalAlignmentMode didSet update()
var dontUpdate = false
var shouldShowBorder:Bool = false didSet update()
//display objects
var rect:SKShapeNode?
var labels:[SKLabelNode] = []

init(text:String, labelWidth:Int, pos:CGPoint, fontName:String="ChalkboardSE-Regular",fontSize:CGFloat=10,fontColor:UIColor=UIColor.blackColor(),leading:Int=10, alignment:SKLabelHorizontalAlignmentMode = .Center, shouldShowBorder:Bool = false)

    self.text = text
    self.labelWidth = labelWidth
    self.pos = pos
    self.fontName = fontName
    self.fontSize = fontSize
    self.fontColor = fontColor
    self.leading = leading
    self.shouldShowBorder = shouldShowBorder
    self.alignment = alignment

    super.init()

    self.update()


//if you want to change properties without updating the text field,
//  set dontUpdate to false and call the update method manually.
func update() 
    if (dontUpdate) return
    if (labels.count>0) 
        for label in labels 
            label.removeFromParent()
        
        labels = []
    
    let separators = NSCharacterSet.whitespaceAndNewlineCharacterSet()
    let words = text.componentsSeparatedByCharactersInSet(separators)

    let len = countElements(text)

    var finalLine = false
    var wordCount = -1
    var lineCount = 0
    while (!finalLine) 
        lineCount++
        var lineLength = CGFloat(0)
        var lineString = ""
        var lineStringBeforeAddingWord = ""

        // creation of the SKLabelNode itself
        var label = SKLabelNode(fontNamed: fontName)
        // name each label node so you can animate it if u wish
        label.name = "line\(lineCount)"
        label.horizontalAlignmentMode = alignment
        label.fontSize = fontSize
        label.fontColor = UIColor.whiteColor()

        while lineLength < CGFloat(labelWidth)
        
            wordCount++
            if wordCount > words.count-1
            
                //label.text = "\(lineString) \(words[wordCount])"
                finalLine = true
                break
            
            else
            
                lineStringBeforeAddingWord = lineString
                lineString = "\(lineString) \(words[wordCount])"
                label.text = lineString
                lineLength = label.width
            
        
        if lineLength > 0 
            wordCount--
            if (!finalLine) 
                lineString = lineStringBeforeAddingWord
            
            label.text = lineString
            var linePos = pos
            if (alignment == .Left) 
                linePos.x -= CGFloat(labelWidth / 2)
             else if (alignment == .Right) 
                linePos.x += CGFloat(labelWidth / 2)
            
            linePos.y += CGFloat(-leading * lineCount)
            label.position = CGPointMake( linePos.x , linePos.y )
            self.addChild(label)
            labels.append(label)
            //println("was \(lineLength), now \(label.width)")
        

    
    labelHeight = lineCount * leading
    showBorder()

func showBorder() 
    if (!shouldShowBorder) return
    if let rect = self.rect 
        self.removeChildrenInArray([rect])
    
    self.rect = SKShapeNode(rectOfSize: CGSize(width: labelWidth, height: labelHeight))
    if let rect = self.rect 
        rect.strokeColor = UIColor.whiteColor()
        rect.lineWidth = 1
        rect.position = CGPoint(x: pos.x, y: pos.y - (CGFloat(labelHeight) / 2.0))
        self.addChild(rect)
    



编辑: 您也可以查看this version,因为它已针对 Swift2 进行了更新

【讨论】:

这样做的一个问题是 SKLabelNode 不像 SKSpriteNode 那样批量渲染。因此,如果您有 20 行标签,则需要 20 次绘制通道,这可能会影响性能。您可以尝试向 SKEffectNode 添加多标签实例,然后对其进行栅格化。这会将多行标签渲染所需的绘制通道减少到 1。 到目前为止,我还没有注意到它存在极端的性能问题。不过,我并没有过度使用多行标签,所以你可能是对的。 感谢您的努力,不要误会我的意思,但您无法处理某些情况。传递比labelWidth 更长的字符串将进入无限循环(在说话的那一刻)。 我在 Gist 上的解决方案(在上面的答案中引用)现在已针对 Swift 3 进行了更新。gist.github.com/craiggrummitt/03bfa93c07e247ee9358

以上是关于swift 2 sprite-kit 中的多行标签?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 uilabel 中使用多行并根据 Swift 中的标签高度自动扩展 uitableview 行高?

sprite-kit swift字符选择菜单?

Sprite-Kit 为单个接触注册多个碰撞

Swift 3 - 调整字体大小以适应宽度,多行

Sprite-kit 主要角色选择器

使用故事板、自动布局和 Swift 的多行 UILabel 和 UITextView