Visual_Novel_iOS/crush/Crush/Src/Components/UI/Label/LineSpaceLabel.swift

133 lines
4.3 KiB
Swift
Raw Normal View History

2025-10-09 10:29:35 +00:00
//
// LineSpaceLabel.swift
// Crush
//
// Created by Leon on 2025/7/18.
//
import UIKit
class LineSpaceLabel: UILabel {
// MARK: - Properties
var paragraphSpace: CGFloat = 0
private var typography: EPTypography?
private var typographyText: String?
// MARK: - Initialization
override init(frame: CGRect) {
super.init(frame: frame)
numberOfLines = 0
textColor = .text
guard let text = typographyText, !text.isEmpty else { return }
self.text = text
}
@available(*, unavailable)
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: - Public Methods (Way 1)
func setupLineSpace(_ space: CGFloat) {
guard let text = text, !text.isEmpty else {
assertionFailure("self.text should not be empty.")
return
}
let attributedString: NSMutableAttributedString
if let existingAttributedText = attributedText {
attributedString = NSMutableAttributedString(attributedString: existingAttributedText)
} else {
attributedString = NSMutableAttributedString(string: text)
}
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = space
attributedString.addAttribute(.paragraphStyle, value: paragraphStyle, range: NSRange(location: 0, length: text.count))
self.text = nil
attributedText = attributedString
lineBreakMode = .byTruncatingTail
}
func setupText(_ text: String?, lineSpace: CGFloat) {
let safeText = text ?? ""
let attributedString = NSMutableAttributedString(string: safeText)
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = lineSpace
attributedString.addAttribute(.paragraphStyle, value: paragraphStyle, range: NSRange(location: 0, length: safeText.count))
attributedText = attributedString
lineBreakMode = .byTruncatingTail
}
func setupHighlightText(_ highlight: String?, color: UIColor) {
guard let attributedText = attributedText, let highlight = highlight, !highlight.isEmpty else {
assertionFailure("attributedText and highlight must be valid")
return
}
let attributedString = NSMutableAttributedString(attributedString: attributedText)
if let range = attributedString.string.range(of: highlight) {
let nsRange = NSRange(range, in: attributedString.string)
attributedString.addAttribute(.foregroundColor, value: color, range: nsRange)
}
self.attributedText = attributedString
}
// MARK: - Public Methods (Way 2)
func config(_ typography: EPTypography) {
self.typography = typography
self.text = text
}
// MARK: - Overrides
override var text: String? {
get { super.text }
set {
let safeText = newValue ?? ""
if let typography = typography {
typographyText = safeText
let attributes: [NSAttributedString.Key: Any] = [
.font: typography.font!,
.foregroundColor: textColor ?? .black,
]
let attributedString = NSMutableAttributedString(string: safeText, attributes: attributes)
let calLineHeight = typography.lineHeight * 0.5 // Temporary conversion, may need testing
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = calLineHeight
paragraphStyle.alignment = textAlignment
if paragraphSpace > 0 {
paragraphStyle.paragraphSpacing = paragraphSpace
}
attributedString.addAttribute(.paragraphStyle, value: paragraphStyle, range: NSRange(location: 0, length: safeText.count))
self.attributedText = attributedString
self.lineBreakMode = .byTruncatingTail
layoutIfNeeded()
} else {
super.text = safeText
}
}
}
override var textColor: UIColor! {
get { super.textColor }
set {
super.textColor = newValue
if let typographyText = typographyText, !typographyText.isEmpty {
text = typographyText
}
}
}
}