-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathSTLabel.swift
More file actions
223 lines (191 loc) · 7.78 KB
/
Copy pathSTLabel.swift
File metadata and controls
223 lines (191 loc) · 7.78 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
//
// STLabel.swift
// STBaseProject
//
// Created by 寒江孤影 on 2017/10/14.
//
import UIKit
private enum STLabelLocalizationKey {
static var localizedTextKey: UInt8 = 0
}
public enum STLabelVerticalAlignment {
case top
case middle
case bottom
}
@IBDesignable
open class STLabel: UILabel, STLocalizable {
private var verticalAlignment: STLabelVerticalAlignment?
public var contentEdgeInsets: UIEdgeInsets = .zero {
didSet {
invalidateIntrinsicContentSize()
setNeedsLayout()
}
}
@IBInspectable open var contentInsetTop: CGFloat {
get { return self.contentEdgeInsets.top }
set { self.contentEdgeInsets.top = max(0, newValue) }
}
@IBInspectable open var contentInsetLeft: CGFloat {
get { return self.contentEdgeInsets.left }
set { self.contentEdgeInsets.left = max(0, newValue) }
}
@IBInspectable open var contentInsetBottom: CGFloat {
get { return self.contentEdgeInsets.bottom }
set { self.contentEdgeInsets.bottom = max(0, newValue) }
}
@IBInspectable open var contentInsetRight: CGFloat {
get { return self.contentEdgeInsets.right }
set { self.contentEdgeInsets.right = max(0, newValue) }
}
@IBInspectable open var localizedText: String {
get {
return objc_getAssociatedObject(self, &STLabelLocalizationKey.localizedTextKey) as? String ?? ""
}
set {
objc_setAssociatedObject(self, &STLabelLocalizationKey.localizedTextKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
self.text = newValue.localized
}
}
/// 优先使用 localizedText 存储的原始 key 重新本地化,支持运行时语言切换。
/// 未通过 localizedText 设置 key 时不处理(避免将动态赋值的 text 误作 key 查询)。
public func st_updateLocalizedText() {
let key = self.localizedText
guard !key.isEmpty else { return }
self.text = key.localized
}
@IBInspectable open var cornerRadius: CGFloat {
get {
return layer.cornerRadius
}
set {
self.layer.cornerRadius = newValue
self.st_updateLiquidGlassCornerRadius()
}
}
@IBInspectable open var clipsContentToBounds: Bool {
get {
return self.layer.masksToBounds
}
set {
self.layer.masksToBounds = newValue
}
}
@IBInspectable open var borderWidth: CGFloat {
get {
return layer.borderWidth
}
set {
self.layer.borderWidth = newValue > 0 ? newValue : 0
}
}
@IBInspectable open var borderColor: UIColor? {
get {
guard let color = self.layer.borderColor else { return nil }
return UIColor(cgColor: color)
}
set {
self.layer.borderColor = newValue?.cgColor
}
}
@IBInspectable open var isLiquidGlassEnabled: Bool = false {
didSet {
if self.isLiquidGlassEnabled {
self.updateLiquidGlassBackground()
} else {
self.st_disableLiquidGlassBackground()
}
}
}
@IBInspectable open var liquidGlassTintColor: UIColor = UIColor.white.withAlphaComponent(0.18) {
didSet {
self.updateLiquidGlassBackground()
}
}
@IBInspectable open var liquidGlassHighlightOpacity: Float = 0.45 {
didSet {
self.updateLiquidGlassBackground()
}
}
@IBInspectable open var liquidGlassBorderColor: UIColor = UIColor.white.withAlphaComponent(0.45) {
didSet {
self.updateLiquidGlassBackground()
}
}
public init(frame: CGRect, type: STLabelVerticalAlignment) {
super.init(frame: frame)
self.verticalAlignment = type
self.adjustsFontForContentSizeCategory = true
}
override public init(frame: CGRect) {
super.init(frame: frame)
self.verticalAlignment = STLabelVerticalAlignment.middle
self.adjustsFontForContentSizeCategory = true
}
public required init?(coder: NSCoder) {
super.init(coder: coder)
self.verticalAlignment = STLabelVerticalAlignment.middle
self.adjustsFontForContentSizeCategory = true
self.updateFontSize()
}
override public func layoutSubviews() {
super.layoutSubviews()
self.st_updateLiquidGlassCornerRadius()
if let glassView = self.subviews.first(where: { $0 is STLiquidGlassView }) {
self.sendSubviewToBack(glassView)
}
}
private func updateFontSize() {
self.font = UIFont.st_systemFont(ofSize: self.font.pointSize)
}
override public func textRect(forBounds bounds: CGRect, limitedToNumberOfLines numberOfLines: Int) -> CGRect {
// 考虑内边距调整边界
let adjustedBounds = bounds.inset(by: contentEdgeInsets)
return super.textRect(forBounds: adjustedBounds, limitedToNumberOfLines: numberOfLines)
}
override public func draw(_ rect: CGRect) {
// 考虑内边距调整绘制区域
let adjustedRect = rect.inset(by: contentEdgeInsets)
super.drawText(in: adjustedRect)
}
override public var intrinsicContentSize: CGSize {
// 使用 super 的 intrinsicContentSize 来获取正确的文本尺寸
let originalSize = super.intrinsicContentSize
// 如果原始尺寸为零,尝试手动计算
if originalSize == .zero {
let currentFont = self.font ?? UIFont.st_systemFont(ofSize: UIFont.systemFontSize)
let textSize = self.text?.size(withAttributes: [.font: currentFont]) ?? CGSize.zero
if let attributedText = self.attributedText {
let attributedSize = attributedText.size()
return CGSize(width: attributedSize.width + contentEdgeInsets.left + contentEdgeInsets.right,
height: attributedSize.height + contentEdgeInsets.top + contentEdgeInsets.bottom)
}
return CGSize(width: textSize.width + contentEdgeInsets.left + contentEdgeInsets.right,
height: textSize.height + contentEdgeInsets.top + contentEdgeInsets.bottom)
}
// 在原始尺寸基础上加上内边距
return CGSize(width: originalSize.width + contentEdgeInsets.left + contentEdgeInsets.right,
height: originalSize.height + contentEdgeInsets.top + contentEdgeInsets.bottom)
}
override public func sizeThatFits(_ size: CGSize) -> CGSize {
// 如果可用空间小于内边距,返回最小尺寸
let availableWidth = size.width - contentEdgeInsets.left - contentEdgeInsets.right
let availableHeight = size.height - contentEdgeInsets.top - contentEdgeInsets.bottom
if availableWidth <= 0 || availableHeight <= 0 {
return CGSize(width: contentEdgeInsets.left + contentEdgeInsets.right,
height: contentEdgeInsets.top + contentEdgeInsets.bottom)
}
let adjustedSize = CGSize(width: availableWidth, height: availableHeight)
let originalSize = super.sizeThatFits(adjustedSize)
return CGSize(width: originalSize.width + contentEdgeInsets.left + contentEdgeInsets.right,
height: originalSize.height + contentEdgeInsets.top + contentEdgeInsets.bottom)
}
private func updateLiquidGlassBackground() {
guard self.isLiquidGlassEnabled else { return }
self.st_enableLiquidGlassBackground(
tintColor: self.liquidGlassTintColor,
highlightOpacity: self.liquidGlassHighlightOpacity,
borderColor: self.liquidGlassBorderColor
)
}
}