Restructuring the tappable text feature. Must account of the offset incurred by adding an extra space and image attachment to the overall length of the label. Included a sorting feature to ensure clauses array is always in ascending order by location.
This commit is contained in:
parent
849a4d761a
commit
81ccaa5bbd
@ -18,7 +18,9 @@ public typealias ActionBlock = () -> Void
|
||||
//------------------------------------------------------
|
||||
|
||||
public var makeWholeViewClickable = false
|
||||
fileprivate var hasAttachmentImage = false
|
||||
|
||||
/// Indication that attributed text attachment will affect range location of attributed text.
|
||||
fileprivate var hasAttachmentImageInsideText = false
|
||||
|
||||
/// Set this property if you want updateView to update the font based on this standard and the size passed in.
|
||||
public var standardFontSize: CGFloat = 0.0
|
||||
@ -40,7 +42,17 @@ public typealias ActionBlock = () -> Void
|
||||
//------------------------------------------------------
|
||||
|
||||
public var clauses: [ActionableClause] = [] {
|
||||
didSet { isUserInteractionEnabled = !clauses.isEmpty }
|
||||
didSet {
|
||||
isUserInteractionEnabled = !clauses.isEmpty
|
||||
if clauses.count > 1 {
|
||||
clauses.sort{ first, second in
|
||||
guard let firstLocation = first.range?.location,
|
||||
let secondLocation = second.range?.location
|
||||
else { return false }
|
||||
return firstLocation < secondLocation
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Used for tappable links in the text.
|
||||
@ -212,6 +224,8 @@ public typealias ActionBlock = () -> Void
|
||||
|
||||
let range = NSRange(location: location, length: length)
|
||||
|
||||
print(attributeType)
|
||||
|
||||
switch attributeType {
|
||||
case "underline":
|
||||
attributedString.addAttribute(.underlineStyle, value: NSUnderlineStyle.single.rawValue, range: range)
|
||||
@ -233,7 +247,10 @@ public typealias ActionBlock = () -> Void
|
||||
mutableString.append(NSAttributedString(attachment: imageAttachment))
|
||||
|
||||
attributedString.insert(mutableString, at: location)
|
||||
(label as? Label)?.hasAttachmentImage = true
|
||||
|
||||
if location < attributedString.length {
|
||||
(label as? Label)?.hasAttachmentImageInsideText = true
|
||||
}
|
||||
|
||||
case "font":
|
||||
if let fontStyle = attribute.optionalStringForKey("style") {
|
||||
@ -332,19 +349,20 @@ public typealias ActionBlock = () -> Void
|
||||
attributedString.addAttribute(.font, value: fontObj.withSize(stylerSize) as Any, range: range)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Loop the original attributed string, resize the image attachments.
|
||||
originalAttributedString.enumerateAttribute(.attachment, in: NSRange(location: 0, length: originalAttributedString.length), options: []) { value, range, stop in
|
||||
if value is NSTextAttachment, let attachment = value as? NSTextAttachment,
|
||||
let stylerSize = MFStyler.sizeObjectGeneric(forCurrentDevice: attachment.bounds.width)?.getValueBased(onSize: size) {
|
||||
|
||||
|
||||
let dimension = round(stylerSize)
|
||||
attachment.bounds = CGRect(x: 0, y: 0, width: dimension, height: dimension)
|
||||
}
|
||||
}
|
||||
|
||||
attributedText = attributedString
|
||||
} else if !MVMCoreGetterUtility.fequal(a: Float(standardFontSize), b: 0.0), let sizeObject = self.sizeObject ?? MFStyler.sizeObjectGeneric(forCurrentDevice: standardFontSize) {
|
||||
self.font = self.font.withSize(sizeObject.getValueBased(onSize: size))
|
||||
} else if !MVMCoreGetterUtility.fequal(a: Float(standardFontSize), b: 0.0), let sizeObject = sizeObject ?? MFStyler.sizeObjectGeneric(forCurrentDevice: standardFontSize) {
|
||||
font = font.withSize(sizeObject.getValueBased(onSize: size))
|
||||
}
|
||||
}
|
||||
|
||||
@ -379,8 +397,6 @@ public typealias ActionBlock = () -> Void
|
||||
mutableString.append(NSAttributedString(string: " "))
|
||||
mutableString.append(NSAttributedString(attachment: Label.getTextAttachmentImage(dimension: font.pointSize)))
|
||||
self.attributedText = mutableString
|
||||
|
||||
hasAttachmentImage = true
|
||||
}
|
||||
|
||||
/**
|
||||
@ -403,7 +419,9 @@ public typealias ActionBlock = () -> Void
|
||||
mutableString.insert(NSAttributedString(attachment: Label.getTextAttachmentImage(dimension: font.pointSize)), at: index + 1)
|
||||
self.attributedText = mutableString
|
||||
|
||||
hasAttachmentImage = true
|
||||
if index < attributedText.length {
|
||||
hasAttachmentImageInsideText = true
|
||||
}
|
||||
}
|
||||
|
||||
static func getTextAttachmentImage(dimension: CGFloat) -> NSTextAttachment {
|
||||
@ -425,7 +443,7 @@ extension Label {
|
||||
text = nil
|
||||
attributedText = nil
|
||||
originalAttributedString = nil
|
||||
hasAttachmentImage = false
|
||||
hasAttachmentImageInsideText = false
|
||||
styleB2(true)
|
||||
}
|
||||
|
||||
@ -528,8 +546,36 @@ extension Label {
|
||||
|
||||
@objc private func textLinkTapped(_ gesture: UITapGestureRecognizer) {
|
||||
|
||||
var offset = 0
|
||||
var attachmentLocations: [Int] = []
|
||||
var attachmentIndex = 0
|
||||
|
||||
// Used to identify all images attached in the label.
|
||||
if hasAttachmentImageInsideText {
|
||||
attributedText?.enumerateAttribute(.attachment, in: NSRange(location: 0, length: attributedText!.length), options: []) { value, range, stop in
|
||||
guard value is NSTextAttachment else { return }
|
||||
|
||||
attachmentLocations.append(range.location)
|
||||
|
||||
if range.location == 0 {
|
||||
offset = 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for clause in clauses {
|
||||
if let range = clause.range, gesture.didTapAttributedTextInLabel(self, inRange: range) {
|
||||
guard let range = clause.range else { return }
|
||||
|
||||
// Must increment an offset becuase every image added to text interior increases text length by 1 or 2 depending on location.
|
||||
if hasAttachmentImageInsideText {
|
||||
if range.location > attachmentLocations[attachmentIndex] {
|
||||
offset += 2
|
||||
attachmentIndex += 1
|
||||
}
|
||||
}
|
||||
|
||||
// This determines if we tapped on the desired range of text.
|
||||
if gesture.didTapAttributedTextInLabel(self, inRange: range, offset: offset) {
|
||||
clause.performAction()
|
||||
return
|
||||
}
|
||||
@ -540,31 +586,17 @@ extension Label {
|
||||
// MARK: -
|
||||
extension UITapGestureRecognizer {
|
||||
|
||||
func didTapAttributedTextInLabel(_ label: Label, inRange targetRange: NSRange) -> Bool {
|
||||
func didTapAttributedTextInLabel(_ label: Label, inRange targetRange: NSRange, offset: Int) -> Bool {
|
||||
|
||||
if label.makeWholeViewClickable {
|
||||
return true
|
||||
}
|
||||
|
||||
guard let attributedText = label.attributedText, let font = label.font else { return false }
|
||||
|
||||
var fontToAnalyze: UIFont? = font
|
||||
|
||||
// Necessary where label text is not consistent in font.
|
||||
for attr in attributedText.attributes(at: targetRange.location, effectiveRange: nil) {
|
||||
if attr.key == NSAttributedString.Key.font {
|
||||
fontToAnalyze = attr.value as? UIFont
|
||||
}
|
||||
}
|
||||
|
||||
let range = label.hasAttachmentImage ? NSRange(location: 0, length: attributedText.length) : targetRange
|
||||
|
||||
let mutableAttribString = NSMutableAttributedString(attributedString: attributedText)
|
||||
mutableAttribString.addAttributes([NSAttributedString.Key.font: fontToAnalyze as Any], range: range)
|
||||
|
||||
guard let attributedText = label.attributedText else { return false }
|
||||
|
||||
let textStorage = NSTextStorage(attributedString: attributedText)
|
||||
let layoutManager = NSLayoutManager()
|
||||
let textContainer = NSTextContainer(size: .zero)
|
||||
let textStorage = NSTextStorage(attributedString: mutableAttribString)
|
||||
|
||||
layoutManager.addTextContainer(textContainer)
|
||||
textStorage.addLayoutManager(layoutManager)
|
||||
@ -576,6 +608,11 @@ extension UITapGestureRecognizer {
|
||||
|
||||
let indexOfGlyph = layoutManager.glyphIndex(for: location(in: label), in: textContainer)
|
||||
|
||||
if label.hasAttachmentImageInsideText {
|
||||
let location = targetRange.location + offset
|
||||
return NSLocationInRange(indexOfGlyph, NSRange(location: location, length: targetRange.length))
|
||||
}
|
||||
|
||||
return NSLocationInRange(indexOfGlyph, targetRange)
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user