gpt4 book ai didi

ios - CATextLayer 渲染具有截断和段落样式的 AttributedString

转载 作者:行者123 更新时间:2023-12-01 17:04:02 24 4
gpt4 key购买 nike

我正在尝试创建一个具有动画属性的自定义标签,所以我决定使用 CATextLayer 而不是直接使用 CoreText..

我想出了下面的代码(我用 playground 来测试东西):

//: A UIKit based Playground for presenting user interface

import UIKit
import PlaygroundSupport


public extension CGRect {
public static func centerRect(_ rectToCenter: CGRect, in rect: CGRect) -> CGRect {
return CGRect(x: rect.origin.x + ((rect.width - rectToCenter.width) / 2.0),
y: rect.origin.y + ((rect.height - rectToCenter.height) / 2.0),
width: rectToCenter.width,
height: rectToCenter.height)
}
}

class MyLabel : UIView {
private let textLayer = CATextLayer()
public var textColor: UIColor = UIColor.black
public var font: UIFont = UIFont.systemFont(ofSize: 17.0)
private var _lineBreak: NSLineBreakMode = .byTruncatingTail


init() {
super.init(frame: .zero)
self.text = nil
self.textAlignment = .natural
self.lineBreakMode = .byTruncatingTail
self.textLayer.isWrapped = true

self.layer.addSublayer(self.textLayer)
}

@available(*, unavailable)
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}


//Update the CATextLayer's attributed string when this property is set..
public var text: String? {

//Getter just returns the CATextLayer's string
get {
if let attrString = self.textLayer.string as? NSAttributedString {
return attrString.string
}

return self.textLayer.string as? String
}

//Setter creates an attributed string with paragraph style..
//Font and colour..
set {
if let value = newValue {
let paragraphStyle = NSParagraphStyle.default.mutableCopy() as! NSMutableParagraphStyle
paragraphStyle.alignment = self.textAlignment
paragraphStyle.lineBreakMode = self.lineBreakMode

self.textLayer.string = NSMutableAttributedString(string: value, attributes: [
.foregroundColor: self.textColor,
.font: self.font])
}
else {
self.textLayer.string = nil
}
}
}

//Convert NSTextAlignment to kCAAlignment String for CATextLayer
public var textAlignment: NSTextAlignment {
get {
switch self.textLayer.alignmentMode {
case kCAAlignmentLeft:
return .left

case kCAAlignmentCenter:
return .center

case kCAAlignmentRight:
return .right

case kCAAlignmentJustified:
return .justified

default:
return .natural
}
}

set {
switch newValue {
case .left:
self.textLayer.alignmentMode = kCAAlignmentLeft

case .center:
self.textLayer.alignmentMode = kCAAlignmentCenter

case .right:
self.textLayer.alignmentMode = kCAAlignmentRight

case .justified:
self.textLayer.alignmentMode = kCAAlignmentJustified

default:
self.textLayer.alignmentMode = kCAAlignmentNatural
}
}
}

//Convert NSLineBreakMode to kCAAlignmentMode String
public var lineBreakMode: NSLineBreakMode {
get {
return _lineBreak
}

set {
_lineBreak = newValue

switch newValue {
case .byWordWrapping:
self.textLayer.isWrapped = true
self.textLayer.truncationMode = kCATruncationNone

case .byCharWrapping:
self.textLayer.isWrapped = true
self.textLayer.truncationMode = kCATruncationNone

case .byClipping:
self.textLayer.isWrapped = false
self.textLayer.truncationMode = kCATruncationNone

case .byTruncatingHead:
self.textLayer.truncationMode = kCATruncationStart

case .byTruncatingMiddle:
self.textLayer.truncationMode = kCATruncationMiddle

case .byTruncatingTail:
self.textLayer.truncationMode = kCATruncationEnd
}
}
}


//Override layoutSubviews to render the CATextLayer..
internal override func layoutSubviews() {
super.layoutSubviews()

//Calculate attributed string size..
let string = self.textLayer.string as! NSAttributedString
var rect = string.boundingRect(with: self.bounds.size, options: [.usesLineFragmentOrigin, .usesFontLeading], context: nil)

//If you change dy to 1.0, Text will render weirdly!
rect = rect.insetBy(dx: 0.0, dy: 0.0)

//Render the textLayer by centering it in its parent..
self.textLayer.contentsScale = UIScreen.main.scale
self.textLayer.rasterizationScale = UIScreen.main.scale
self.textLayer.frame = CGRect.centerRect(rect, in: self.bounds)
self.textLayer.backgroundColor = UIColor.lightGray.cgColor
}

//Somehow always returns 21.. ={
//Not used right now because it doesn't work.. at all..
private func sizeOfTextThatFits(size: CGSize) -> CGSize {
if let string = self.textLayer.string as? NSAttributedString {
let path = CGMutablePath()
path.addRect(CGRect(x: 0.0, y: 0.0, width: size.width, height: size.height))

let frameSetter = CTFramesetterCreateWithAttributedString(string as CFAttributedString)
let frame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, 0), path, nil)
let lines = CTFrameGetLines(frame) as NSArray

var lineWidth: CGFloat = 0.0
var yOffset: CGFloat = 0.0

for line in lines {
let ctLine = line as! CTLine
var ascent: CGFloat = 0.0
var descent: CGFloat = 0.0
var leading: CGFloat = 0.0
lineWidth = CGFloat(max(CTLineGetTypographicBounds(ctLine, &ascent, &descent, &leading), Double(lineWidth)))
yOffset += ascent + descent + leading;
}
return CGSize(width: lineWidth, height: yOffset)
}
return .zero
}
}


class MyViewController : UIViewController {
override func loadView() {
let view = UIView()
view.backgroundColor = .white

let label = MyLabel()
label.backgroundColor = UIColor.red
label.frame = CGRect(x: 150, y: 200, width: 200, height: 200)
label.text = "Hello World! Hello World! Hello World! Hello World! Hello World! Hello World!Hello World! Hello World! Hello World! Hello World! Hello World! Hello World!Hello World! Hello World! Hello World! Hello World! Hello World! Hello World!Hello World! Hello World! Hello World! Hello World! Hello World! Hello World!Hello World! Hello World! Hello World! Hello World! Hello World! Hello World!Hello World! Hello World! Hello World! Hello World! Hello World! Hello World!Hello World! Hello World! Hello World! Hello World! Hello World! Hello World!Hello World! Hello World! Hello World! Hello World! Hello World! Hello World!Hello World! Hello World! Hello World! Hello World! Hello World! Hello World!Hello World! Hello World! Hello World! Hello World! Hello World! Hello World!Hello World! Hello World! Hello World! Hello World! Hello World! Hello World!"
label.textColor = .black

view.addSubview(label)
self.view = view
}
}
// Present the view controller in the Live View window
PlaygroundPage.current.liveView = MyViewController()

问题是,如果我使用 NSParagraphStyle,它根本不会正确渲染或计算大小!

如果我删除段落样式,它可以很好地呈现,但从不遵守换行模式,并且大小不正确..

知道我做错了什么吗?我怎样才能让它服从段落样式的换行模式?为什么在应用段落样式时它总是计算大小为 21?

使用段落样式时: enter image description here

删除段落样式时: enter image description here

当删除段落样式但在 CATextLayer 上设置 TruncateEnd 时(它永远不会截断并且最后一行与倒数第二行之间的间距更大): enter image description here

最佳答案

我发现结束省略号字形不是从属性字符串中获取它的大小,而是从 CATextLayer.fontSize 属性中获取它的大小。

这似乎默认为一个很大的值,这解释了您的文本在您的第一个示例中被向下移动和剪裁。向下扩展文本层的框架大小,设置CATextLayerisWrapped=false,您将看到您的文本加上一个巨大的...省略号字形!

设置 CATextLayer.fontSize 以匹配属性文本的字体大小可以解决此问题,但它看起来像是一个 Apple 错误。

我也无法通过单独设置属性字符串属性来使其工作..

关于ios - CATextLayer 渲染具有截断和段落样式的 AttributedString,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48482657/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com