@@ -53,39 +53,64 @@ final public class LCLabel: UIView {
5353 /// A LCLabel delegate that responses to link interactions within
5454 /// the view
5555 public weak var delegate : LCLabelDelegate ?
56+ public override var frame : CGRect {
57+ didSet {
58+ refreshView ( )
59+ }
60+ }
5661 /// Text ``Alignment`` within the frame
57- public var textAlignment : LCLabel . Alignment = . center
62+ public var textAlignment : LCLabel . Alignment = . center {
63+ didSet {
64+ refreshView ( )
65+ }
66+ }
5867 /// Texts inset within the Frame
5968 public var textInsets : UIEdgeInsets = . zero {
6069 didSet {
61- layoutIfNeeded ( )
70+ refreshView ( )
6271 }
6372 }
6473 /// The attributes to apply to links.
6574 public var linkAttributes : [ NSAttributedString . Key : Any ] ? {
6675 didSet {
6776 guard renderedStorage != nil else { return }
6877 setupRenderStorage ( )
69- layoutIfNeeded ( )
78+ refreshView ( )
7079 }
7180 }
7281 /// Exclues underlines attributes from text
7382 public var shouldExcludeUnderlinesFromText = true {
7483 didSet {
7584 guard renderedStorage != nil else { return }
7685 setupRenderStorage ( )
77- layoutIfNeeded ( )
86+ refreshView ( )
7887 }
7988 }
8089 /// Validates if the user passed an attributed string of type .link and switches
8190 /// it to .lclabelLink
82- public var linkStyleValidation : LinksStyleValidation = . skip
91+ public var linkStyleValidation : LinksStyleValidation = . skip {
92+ didSet {
93+ refreshView ( )
94+ }
95+ }
8396 /// Line breaking mode the label uses, default is `.byTruncatingTail`
84- public var lineBreakMode : NSLineBreakMode = . byTruncatingTail
97+ public var lineBreakMode : NSLineBreakMode = . byTruncatingTail {
98+ didSet {
99+ refreshView ( )
100+ }
101+ }
85102 /// Line padding at the beginning of the view
86- public var lineFragmentPadding : CGFloat = 0
103+ public var lineFragmentPadding : CGFloat = 0 {
104+ didSet {
105+ refreshView ( )
106+ }
107+ }
87108 /// Number of lines allowed
88- public var numberOfLines = 1
109+ public var numberOfLines = 1 {
110+ didSet {
111+ refreshView ( )
112+ }
113+ }
89114 /// Text to be displayed
90115 public var attributedText : NSAttributedString ? {
91116 get {
@@ -102,14 +127,13 @@ final public class LCLabel: UIView {
102127 isHidden = true
103128 }
104129 setupRenderStorage ( )
105- layoutIfNeeded ( )
106- setNeedsLayout ( )
107- setNeedsDisplay ( )
130+ refreshView ( )
108131 }
109132 }
110133
111134 /// Current text to be displayed
112- private var renderedStorage : NSTextStorage !
135+ private var renderedStorage : NSTextStorage ?
136+ private var textContainer : NSTextContainer ?
113137 private var currentCalculatedFrame : CGRect ?
114138
115139 /// Current LayoutManager
@@ -124,12 +148,10 @@ final public class LCLabel: UIView {
124148
125149 public init ( ) {
126150 super. init ( frame: . zero)
127- setupLabel ( )
128151 }
129152
130153 public override init ( frame: CGRect ) {
131154 super. init ( frame: frame)
132- setupLabel ( )
133155 }
134156
135157 public required init ? ( coder: NSCoder ) {
@@ -146,19 +168,28 @@ final public class LCLabel: UIView {
146168 return
147169 }
148170
149- // Removes the current text container and replace it with a newer one
150- if !layoutManager. textContainers. isEmpty {
151- layoutManager. removeTextContainer ( at: 0 )
152- }
153-
154171 let bounds = textRect ( forBounds: rect)
155172
156173 currentCalculatedFrame = bounds
157- let container = NSTextContainer ( size: bounds. size)
174+
175+ let container : NSTextContainer
176+ // Check if the current text container is still valid
177+ // with the proper size.
178+ if let textContainer = textContainer,
179+ textContainer. size == bounds. size
180+ {
181+ container = textContainer
182+ } else {
183+ // Removes the current text container and replace it with a newer one
184+ if !layoutManager. textContainers. isEmpty {
185+ layoutManager. removeTextContainer ( at: 0 )
186+ }
187+ container = NSTextContainer ( size: bounds. size)
188+ layoutManager. addTextContainer ( container)
189+ }
158190 container. maximumNumberOfLines = numberOfLines
159191 container. lineBreakMode = lineBreakMode
160192 container. lineFragmentPadding = lineFragmentPadding
161- layoutManager. addTextContainer ( container)
162193 storage. addLayoutManager ( layoutManager)
163194 let range = layoutManager. glyphRange ( for: container)
164195
@@ -197,12 +228,9 @@ final public class LCLabel: UIView {
197228 return newBounds
198229 }
199230
200- private func setupLabel( ) {
201- let tapGesture = UILongPressGestureRecognizer (
202- target: self ,
203- action: #selector( handleUserInput) )
204- tapGesture. delegate = self
205- addGestureRecognizer ( tapGesture)
231+ private func refreshView( ) {
232+ setNeedsDisplay ( )
233+ setNeedsLayout ( )
206234 }
207235
208236 /// The following functions replaces
@@ -297,37 +325,6 @@ extension LCLabel {
297325 return getLink ( at: touch. location ( in: self ) )
298326 }
299327
300- }
301-
302- // MARK: - UIGestureRecognizerDelegate
303-
304- extension LCLabel : UIGestureRecognizerDelegate {
305-
306- public func gestureRecognizer(
307- _ gestureRecognizer: UIGestureRecognizer ,
308- shouldReceive touch: UITouch ) -> Bool
309- {
310- return getLink ( at: touch. location ( in: self ) ) != nil
311- }
312-
313- @objc
314- private func handleUserInput( _ gesture: UILongPressGestureRecognizer ) {
315- let point = gesture. location ( in: self )
316- switch gesture. state {
317- case . began:
318- checkoutLink ( at: point)
319- default :
320- break
321- }
322- }
323-
324- private func checkoutLink( at point: CGPoint ) {
325- guard let url = getLink ( at: point) else {
326- return
327- }
328- delegate? . didPress ( url: url, at: point)
329- }
330-
331328 private func getLink( at point: CGPoint ) -> URL ? {
332329 // Check if the point is within the bounds of the text
333330 // container before converting it
@@ -354,7 +351,7 @@ extension LCLabel: UIGestureRecognizerDelegate {
354351 // .link attribute at an index (x)
355352 // (Note): we are using attachment since i couldnt remove the default
356353 // link coloring with TextKit
357- guard let url = renderedStorage. attribute (
354+ guard let url = renderedStorage? . attribute (
358355 . lclabelLink,
359356 at: index,
360357 effectiveRange: nil )
0 commit comments