@@ -11,8 +11,21 @@ extension UIFont {
1111/// An enumeration that represents the content of a `Text` component.
1212/// It can either be a plain `String` or an `NSAttributedString` for more complex styling.
1313public enum TextContent {
14- case string( String )
14+ case string( String , UIFont )
1515 case attributedString( NSAttributedString )
16+
17+ func apply( to label: UILabel ) {
18+ switch self {
19+ case . string( let string, let font) :
20+ label. attributedText = nil
21+ label. font = font
22+ label. text = string
23+ case . attributedString( let string) :
24+ label. font = nil
25+ label. text = nil
26+ label. attributedText = string
27+ }
28+ }
1629}
1730
1831/// A shared UILabel instance used for sizing text when `useSharedLabelForSizing` is true.
@@ -48,7 +61,7 @@ public struct Text: Component {
4861 numberOfLines: Int = 0 ,
4962 lineBreakMode: NSLineBreakMode = . byWordWrapping
5063 ) {
51- self . content = . string( text)
64+ self . content = . string( text, UIFont . systemFont ( ofSize : UIFont . systemFontSize ) )
5265 self . numberOfLines = numberOfLines
5366 self . lineBreakMode = lineBreakMode
5467 self . isSwiftAttributedString = false
@@ -109,32 +122,32 @@ public struct Text: Component {
109122 /// - Parameter constraint: The constraints to use for laying out the text.
110123 /// - Returns: A `TextRenderNode` that represents the laid out text.
111124 public func layout( _ constraint: Constraint ) -> TextRenderNode {
112- let attributedString : NSAttributedString
113- switch content {
114- case . string( let string) :
115- attributedString = NSAttributedString ( string: string, attributes: [ . font: font, . foregroundColor: textColor] )
116- case . attributedString( let string) :
117- attributedString = string
118- }
119125 if Self . useSharedLabelForSizing, Thread . isMainThread {
126+ // Fastest route, but not thread safe.
120127 layoutLabel. numberOfLines = numberOfLines
121128 layoutLabel. lineBreakMode = lineBreakMode
122- switch content {
123- case . string( let string) :
124- layoutLabel. font = font
125- layoutLabel. text = string
126- case . attributedString( let string) :
127- layoutLabel. font = nil
128- layoutLabel. attributedText = string
129- }
129+ content. apply ( to: layoutLabel)
130130 let size = layoutLabel. sizeThatFits ( constraint. maxSize)
131131 return TextRenderNode (
132- attributedString : attributedString ,
132+ content : content ,
133133 numberOfLines: numberOfLines,
134134 lineBreakMode: lineBreakMode,
135135 size: size. bound ( to: constraint)
136136 )
137137 }
138+
139+ let attributedString : NSAttributedString
140+ switch content {
141+ case . string( let string, let font) :
142+ var attributes : [ NSAttributedString . Key : Any ] = [ . font: self . font ?? font]
143+ if let color = textColor {
144+ attributes [ . foregroundColor] = color
145+ }
146+ attributedString = NSAttributedString ( string: string, attributes: attributes)
147+ case . attributedString( let string) :
148+ attributedString = string
149+ }
150+
138151 if numberOfLines != 0 || isSwiftAttributedString {
139152 // Slower route
140153 //
@@ -154,7 +167,7 @@ public struct Text: Component {
154167 layoutManager. ensureLayout ( for: textContainer)
155168 let rect = layoutManager. usedRect ( for: textContainer)
156169 return TextRenderNode (
157- attributedString : attributedString ,
170+ content : content ,
158171 numberOfLines: numberOfLines,
159172 lineBreakMode: lineBreakMode,
160173 size: rect. size. bound ( to: constraint)
@@ -165,7 +178,7 @@ public struct Text: Component {
165178 options: [ . usesLineFragmentOrigin] ,
166179 context: nil ) . size
167180 return TextRenderNode (
168- attributedString : attributedString ,
181+ content : content ,
169182 numberOfLines: numberOfLines,
170183 lineBreakMode: lineBreakMode,
171184 size: size. bound ( to: constraint)
@@ -177,7 +190,7 @@ public struct Text: Component {
177190/// A `TextRenderNode` represents a renderable text node with styling and layout information.
178191public struct TextRenderNode : RenderNode {
179192 /// The styled text to be rendered.
180- public let attributedString : NSAttributedString
193+ public let content : TextContent
181194 /// The maximum number of lines to use for rendering. 0 means no limit.
182195 public let numberOfLines : Int
183196 /// The technique to use for wrapping and truncating the text.
@@ -187,12 +200,12 @@ public struct TextRenderNode: RenderNode {
187200
188201 /// Initializes a new `TextRenderNode` with the given parameters.
189202 /// - Parameters:
190- /// - attributedString : The styled text to be rendered.
203+ /// - content : The styled text to be rendered.
191204 /// - numberOfLines: The maximum number of lines to use for rendering.
192205 /// - lineBreakMode: The technique to use for wrapping and truncating the text.
193206 /// - size: The calculated size of the rendered text.
194- public init ( attributedString : NSAttributedString , numberOfLines: Int , lineBreakMode: NSLineBreakMode , size: CGSize ) {
195- self . attributedString = attributedString
207+ public init ( content : TextContent , numberOfLines: Int , lineBreakMode: NSLineBreakMode , size: CGSize ) {
208+ self . content = content
196209 self . numberOfLines = numberOfLines
197210 self . lineBreakMode = lineBreakMode
198211 self . size = size
@@ -201,7 +214,7 @@ public struct TextRenderNode: RenderNode {
201214 /// Updates the provided `UILabel` with the render node's properties.
202215 /// - Parameter label: The `UILabel` to update with the text rendering information.
203216 public func updateView( _ label: UILabel ) {
204- label . attributedText = attributedString
217+ content . apply ( to : label )
205218 label. numberOfLines = numberOfLines
206219 label. lineBreakMode = lineBreakMode
207220 }
0 commit comments