获取UILabel中的每一行文本 [英] Get each line of text in a UILabel

查看:160
本文介绍了获取UILabel中的每一行文本的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将 UILabel 中的每一行添加到数组中,但我使用的代码似乎并不十分准确。

I'm trying to add each line in a UILabel to an array, but the code I'm using doesn't appear to be terribly accurate.

func getLinesArrayOfStringInLabel(label:UILabel) -> [String] {

    guard let text: NSString = label.text as? NSString else { return [] }
    let font:UIFont = label.font
    let rect:CGRect = label.frame

    let myFont: CTFont = CTFontCreateWithName(font.fontName as CFString, font.pointSize, nil)

    let attStr:NSMutableAttributedString = NSMutableAttributedString(string: text as String)
    attStr.addAttribute(NSAttributedStringKey.font, value:myFont, range: NSMakeRange(0, attStr.length))

    let frameSetter:CTFramesetter = CTFramesetterCreateWithAttributedString(attStr as CFAttributedString)

    let path: CGMutablePath = CGMutablePath()
    path.addRect(CGRect(x: 0, y: 0, width: rect.size.width, height: 100000))

    let frame:CTFrame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, 0), path, nil)
    let lines = CTFrameGetLines(frame) as NSArray
    var linesArray = [String]()

    for line in lines {
        let lineRange = CTLineGetStringRange(line as! CTLine)
        let range:NSRange = NSMakeRange(lineRange.location, lineRange.length)
        let lineString = text.substring(with: range)
        linesArray.append(lineString as String)
    }
    return linesArray
}


let label = UILabel()
label.numberOfLines = 0
label.frame = CGRect(x: 40, y: 237, width: 265, height: 53)
label.font = UIFont.systemFont(ofSize: 22, weight: UIFont.Weight.regular)
label.text = "Hey there how's it going today?"
label.backgroundColor = .red
bg.addSubview(label)
print(getLinesArrayOfStringInLabel(label: label))

这打印

["Hey there how\'s it going ", "today?"]

但标签看起来像这样:

我希望得到 [嘿那里怎么样它是今天吗?] 。发生了什么?

I expected to get ["Hey there how\'s it ", "going today?"]. What's going on?

推荐答案

所以看起来它与UILabel有关,而且你使用的功能没有问题。我怀疑CATextLayer会渲染它们是如何从该方法返回的,我发现这很遗憾:(我是对的。

So it appears to be something with UILabel and not something wrong with the function you are using. It was my suspicion that a CATextLayer would render the lines how they are returned from that method and I found out sadly :( that I am right.

这是一张照片我的结果:

Here is a picture of my results:

红色是您用来创建UILabel的确切代码。

The red is the exact code you used to create your UILabel.

绿色是CATextLayer,具有上述UILabel的所有相同特征,包括字体,字体大小和帧大小。

The green is a CATextLayer with all of the same characteristics of the UILabel from above including font,fontsize, and frame size.

黄色是一个子类UIView,它正在替换它自己的层并返回一个CATextLayer。我在下面附上它。你可以继续构建它以满足你的需求但我认为这是真正的解决方案,也是唯一一个让得到的线条与用户看到的可见线条相匹配。如果你想出更好的解决方案,请告诉我。

The yellow is a subclassed UIView that is replacing its own layer and returning a CATextLayer. I am attaching it below. You can continue to build it out to meet your needs but I think this is the real solution and the only one that will have the get lines matching the visible lines the user sees. If you come up with a better solution please let me know.

import UIKit

class AGLabel: UIView {

    var alignment : String = kCAAlignmentLeft{
        didSet{
            configureText()
        }
    }
    var font : UIFont = UIFont.systemFont(ofSize: 16){
        didSet{
            configureText()
        }
    }
    var fontSize : CGFloat = 16.0{
        didSet{
            configureText()
        }
    }
    var textColor : UIColor = UIColor.black{
        didSet{
            configureText()
        }
    }

    var text : String = ""{
        didSet{
            configureText()
        }
    }


    override class var layerClass: AnyClass {
        get {
            return CATextLayer.self
        }
    }

    func configureText(){
        if let textLayer = self.layer as? CATextLayer{
            textLayer.foregroundColor = textColor.cgColor
            textLayer.font = font
            textLayer.fontSize = fontSize
            textLayer.string = text
            textLayer.contentsScale = UIScreen.main.scale
            textLayer.contentsGravity = kCAGravityCenter
            textLayer.isWrapped = true
        }
    }
}

您还应该查看核心 - GitHub上的文本标签。它完全像CATextLayers那样呈现,并且与get行的返回相匹配。它不适用于我的特殊需求,因为我需要我的可调整大小并且崩溃但是如果不需要调整大小那么我会检查它。

You should also check out Core-Text-Label on GitHub. It renders exactly as the CATextLayers do and would match the return of the get lines. It won't work for my particular needs as I need mine to be resizable and it crashes but if resizing is not need then I would check it out.

最后我是再回来看来,这可能是在iOS 11中开始的自动换行问题,他们不会在一行上留下孤儿字。

Finally I am back again and it appears that it could be a problem of word wrap that was started in iOS 11 where they do not leave an orphan word on a line.

这篇关于获取UILabel中的每一行文本的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆