Changes made to Label & LabelWithInternalButton.
This commit is contained in:
parent
f04e4de01c
commit
59248974ab
@ -11,20 +11,19 @@ import MVMCore
|
||||
|
||||
public typealias ActionBlock = () -> Void
|
||||
|
||||
|
||||
@objcMembers open class Label: UILabel, MVMCoreViewProtocol, MFButtonProtocol, MVMCoreUIMoleculeViewProtocol {
|
||||
//------------------------------------------------------
|
||||
// MARK: - General Properties
|
||||
//------------------------------------------------------
|
||||
|
||||
// This is here for LabelWithInternalButton
|
||||
public var makeWholeViewClickable = false // TODO: TEST this !
|
||||
|
||||
public var makeWholeViewClickable = 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
|
||||
|
||||
// Set this to use a custom sizing object during updateView instead of the standard.
|
||||
public var sizeObject: MFSizeObject?
|
||||
|
||||
public var scaleSize: NSNumber?
|
||||
|
||||
// Used for scaling the font in updateView.
|
||||
@ -36,33 +35,18 @@ public typealias ActionBlock = () -> Void
|
||||
}
|
||||
|
||||
//------------------------------------------------------
|
||||
// MARK: - For Multi-Action Text
|
||||
// MARK: - Multi-Action Text
|
||||
//------------------------------------------------------
|
||||
|
||||
var didSetGestureRecognizer = false
|
||||
|
||||
public var clauses: [ActionableClause] = [] {
|
||||
didSet {
|
||||
if !didSetGestureRecognizer {
|
||||
isUserInteractionEnabled = true
|
||||
didSetGestureRecognizer = true
|
||||
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(textLinkTapped(_:)))
|
||||
tapGesture.numberOfTapsRequired = 1
|
||||
addGestureRecognizer(tapGesture)
|
||||
}
|
||||
}
|
||||
didSet { isUserInteractionEnabled = !clauses.isEmpty }
|
||||
}
|
||||
|
||||
// Used for tappable links in the text.
|
||||
public struct ActionableClause {
|
||||
var location: Int?
|
||||
var length: Int?
|
||||
var range: NSRange?
|
||||
var actionBlock: ActionBlock?
|
||||
|
||||
var range: NSRange {
|
||||
return NSRange(location: location ?? 0, length: length ?? 0)
|
||||
}
|
||||
|
||||
func performAction() {
|
||||
actionBlock?()
|
||||
}
|
||||
@ -78,6 +62,10 @@ public typealias ActionBlock = () -> Void
|
||||
numberOfLines = 0
|
||||
lineBreakMode = .byWordWrapping
|
||||
translatesAutoresizingMaskIntoConstraints = false
|
||||
|
||||
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(textLinkTapped(_:)))
|
||||
tapGesture.numberOfTapsRequired = 1
|
||||
addGestureRecognizer(tapGesture)
|
||||
}
|
||||
|
||||
@objc public init() {
|
||||
@ -161,8 +149,6 @@ public typealias ActionBlock = () -> Void
|
||||
//------------------------------------------------------
|
||||
|
||||
/**
|
||||
Makes the view interactive and applies the gesture recognizer.
|
||||
|
||||
- Parameters:
|
||||
- label: The label to be set.
|
||||
- html: any html string.
|
||||
@ -184,8 +170,6 @@ public typealias ActionBlock = () -> Void
|
||||
}
|
||||
|
||||
/**
|
||||
Makes the view interactive and applies the gesture recognizer.
|
||||
|
||||
- Parameters:
|
||||
- label: The current label view that will have an actionable range of text.
|
||||
- json: Contains values which det the values of Label.
|
||||
@ -255,22 +239,13 @@ public typealias ActionBlock = () -> Void
|
||||
attributedString.removeAttribute(.font, range: range)
|
||||
attributedString.addAttribute(.font, value: font, range: range)
|
||||
}
|
||||
case "actions":
|
||||
guard let actionLabel = label as? Label,
|
||||
let actions = attribute.optionalArrayForKey("actions")
|
||||
else { continue }
|
||||
case "action":
|
||||
guard let actionLabel = label as? Label else { continue }
|
||||
|
||||
for case let action as [String: Any] in actions {
|
||||
guard let actionLocation = action["location"] as? Int,
|
||||
let actionLength = action["length"] as? Int
|
||||
else { continue }
|
||||
|
||||
actionLabel.clauses.append(ActionableClause(location: actionLocation,
|
||||
length: actionLength,
|
||||
actionBlock: actionLabel.createActionBlockFrom(actionMap: json,
|
||||
additionalData: additionalData,
|
||||
delegate: delegate)))
|
||||
}
|
||||
actionLabel.addActionableClause(range: range,
|
||||
actionMap: json,
|
||||
additionalData: additionalData,
|
||||
delegateObject: delegate)
|
||||
default:
|
||||
continue
|
||||
}
|
||||
@ -279,14 +254,55 @@ public typealias ActionBlock = () -> Void
|
||||
}
|
||||
}
|
||||
|
||||
func createActionBlockFrom(actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, delegate: DelegateObject?) -> ActionBlock {
|
||||
return { [weak delegate] in
|
||||
if (delegate as? MVMCoreUIDelegateObject)?.buttonDelegate?.button?(self, shouldPerformActionWithMap: actionMap, additionalData: additionalData) ?? true {
|
||||
MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegateObject: delegate)
|
||||
/// Reseting to default Label values.
|
||||
@objc public func clearActionableClauses() {
|
||||
|
||||
guard let attributedText = attributedText else { return }
|
||||
let mutableAttributedString = NSMutableAttributedString(attributedString: attributedText)
|
||||
|
||||
clauses.forEach { clause in
|
||||
|
||||
guard let range = clause.range else { return }
|
||||
mutableAttributedString.removeAttribute(NSAttributedString.Key.underlineStyle, range: range)
|
||||
}
|
||||
|
||||
self.attributedText = mutableAttributedString
|
||||
clauses = []
|
||||
}
|
||||
|
||||
public func createActionBlockFrom(actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) -> ActionBlock {
|
||||
return {
|
||||
if (delegateObject as? MVMCoreUIDelegateObject)?.buttonDelegate?.button?(self, shouldPerformActionWithMap: actionMap, additionalData: additionalData) ?? true {
|
||||
MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegateObject: delegateObject)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func addActionableClause(range: NSRange, actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) {
|
||||
|
||||
setDefaultAttributes(range: range)
|
||||
clauses.append(ActionableClause(range: range,
|
||||
actionBlock: createActionBlockFrom(actionMap: actionMap,
|
||||
additionalData: additionalData,
|
||||
delegateObject: delegateObject)))
|
||||
}
|
||||
|
||||
private func addActionableClause(range: NSRange, actionBlock: ActionBlock?) {
|
||||
|
||||
setDefaultAttributes(range: range)
|
||||
clauses.append(ActionableClause(range: range, actionBlock: actionBlock))
|
||||
}
|
||||
|
||||
fileprivate func setDefaultAttributes(range: NSRange) {
|
||||
|
||||
guard let attributedText = attributedText else { return }
|
||||
|
||||
let mutableAttributedString = NSMutableAttributedString(attributedString: attributedText)
|
||||
mutableAttributedString.addAttributes([NSAttributedString.Key.underlineStyle: NSUnderlineStyle.single.rawValue], range: range)
|
||||
|
||||
self.attributedText = mutableAttributedString
|
||||
}
|
||||
|
||||
//------------------------------------------------------
|
||||
// MARK: - Methods
|
||||
//------------------------------------------------------
|
||||
@ -372,6 +388,7 @@ public typealias ActionBlock = () -> Void
|
||||
extension Label {
|
||||
|
||||
@objc public func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: DelegateObject?, additionalData: [AnyHashable: Any]?) {
|
||||
clauses = []
|
||||
Label.setUILabel(self, withJSON: json, delegate: delegateObject, additionalData: additionalData)
|
||||
originalAttributedString = attributedText
|
||||
}
|
||||
@ -394,9 +411,8 @@ extension Label {
|
||||
*/
|
||||
@objc public func addTappableLinkAttribute(range: NSRange, actionBlock: @escaping ActionBlock) {
|
||||
|
||||
clauses.append(ActionableClause(location: range.location,
|
||||
length: range.length,
|
||||
actionBlock: actionBlock))
|
||||
addActionableClause(range: range,
|
||||
actionBlock: actionBlock)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -409,28 +425,29 @@ extension Label {
|
||||
- delegate:
|
||||
- additionalData:
|
||||
*/
|
||||
@objc public func addTappableLinkAttribute(range: NSRange, actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, delegate: DelegateObject?) {
|
||||
@objc public func addTappableLinkAttribute(range: NSRange, actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) {
|
||||
|
||||
clauses.append(ActionableClause(location: range.location,
|
||||
length: range.length,
|
||||
actionBlock: createActionBlockFrom(actionMap: actionMap,
|
||||
additionalData: additionalData,
|
||||
delegate: delegate)))
|
||||
addActionableClause(range: range,
|
||||
actionMap: actionMap,
|
||||
additionalData: additionalData,
|
||||
delegateObject: delegateObject)
|
||||
}
|
||||
|
||||
@objc private func textLinkTapped(_ gesture: UITapGestureRecognizer) {
|
||||
|
||||
for clause in clauses {
|
||||
if gesture.didTapAttributedTextInLabel(self, inRange: clause.range, isWholeViewTappable: makeWholeViewClickable) {
|
||||
if let range = clause.range, gesture.didTapAttributedTextInLabel(self, inRange: range) {
|
||||
clause.performAction()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
extension UITapGestureRecognizer {
|
||||
|
||||
func didTapAttributedTextInLabel(_ label: Label, inRange targetRange: NSRange, isWholeViewTappable: Bool) -> Bool {
|
||||
func didTapAttributedTextInLabel(_ label: Label, inRange targetRange: NSRange) -> Bool {
|
||||
|
||||
guard let attributedText = label.attributedText else { return false }
|
||||
|
||||
@ -444,17 +461,14 @@ extension UITapGestureRecognizer {
|
||||
textContainer.lineFragmentPadding = 0.0
|
||||
textContainer.lineBreakMode = label.lineBreakMode
|
||||
textContainer.maximumNumberOfLines = label.numberOfLines
|
||||
let labelSize = label.bounds.size
|
||||
textContainer.size = labelSize
|
||||
textContainer.size = label.bounds.size
|
||||
|
||||
let indexOfCharacter = layoutManager.characterIndex(for: location(in: label), in: textContainer, fractionOfDistanceBetweenInsertionPoints: nil)
|
||||
|
||||
var range = targetRange
|
||||
|
||||
if isWholeViewTappable, let wholeRange = NSRange(attributedText.string) {
|
||||
range = wholeRange
|
||||
if label.makeWholeViewClickable {
|
||||
return true
|
||||
}
|
||||
|
||||
return NSLocationInRange(indexOfCharacter, range)
|
||||
return NSLocationInRange(indexOfCharacter, targetRange)
|
||||
}
|
||||
}
|
||||
|
||||
@ -24,7 +24,6 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt
|
||||
public var attributedText: NSAttributedString? {
|
||||
willSet(newAttributedText) {
|
||||
if let newAttribText = newAttributedText {
|
||||
|
||||
let mutableAttributedText = NSMutableAttributedString(attributedString: newAttribText)
|
||||
let paragraphStyle = NSMutableParagraphStyle()
|
||||
paragraphStyle.lineSpacing = CGFloat(LabelWithInternalButtonLineSpace)
|
||||
@ -64,18 +63,23 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt
|
||||
if newActionBlock == nil {
|
||||
label?.clauses = []
|
||||
} else {
|
||||
label?.clauses = [Label.ActionableClause(location: actionRange.location,
|
||||
length: actionRange.length,
|
||||
actionBlock: newActionBlock)]
|
||||
label?.clauses = [Label.ActionableClause(range: actionRange, actionBlock: newActionBlock)]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var frontRange: NSRange {
|
||||
return NSRange(location: 0, length: frontText?.count ?? 0)
|
||||
}
|
||||
|
||||
private var actionRange: NSRange {
|
||||
return NSRange(location: frontText?.count ?? 0, length: actionText?.count ?? 0)
|
||||
}
|
||||
|
||||
// Makes entire range of text clickable
|
||||
private var backRange: NSRange {
|
||||
return NSRange(location: (frontText?.count ?? 0) + (actionText?.count ?? 0), length: backText?.count ?? 0)
|
||||
}
|
||||
|
||||
public var makeWholeViewClickable = false {
|
||||
willSet(newBool) {
|
||||
label?.makeWholeViewClickable = newBool
|
||||
@ -165,7 +169,7 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt
|
||||
super.init(frame: .zero)
|
||||
|
||||
setText(fullText, startTag: startTag, endTag: endTag)
|
||||
actionBlock = label?.createActionBlockFrom(actionMap: actionMap, additionalData: additionalData, delegate: delegateObject)
|
||||
actionBlock = label?.createActionBlockFrom(actionMap: actionMap, additionalData: additionalData, delegateObject: delegateObject)
|
||||
}
|
||||
|
||||
//------------------------------------------------------
|
||||
@ -195,12 +199,12 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt
|
||||
setAlternateActionTextAttributes([NSAttributedString.Key.underlineStyle: NSNumber(value: NSUnderlineStyle.single.rawValue)])
|
||||
|
||||
label?.attributedText = attributedText
|
||||
label?.accessibilityTraits = actionText?.isEmpty ?? false ? .staticText : .button
|
||||
label?.accessibilityTraits = actionText?.isEmpty ?? true ? .staticText : .button
|
||||
}
|
||||
|
||||
@objc public func setActionMap(_ actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) {
|
||||
|
||||
actionBlock = label?.createActionBlockFrom(actionMap: actionMap, additionalData: additionalData, delegate: delegateObject)
|
||||
actionBlock = label?.createActionBlockFrom(actionMap: actionMap, additionalData: additionalData, delegateObject: delegateObject)
|
||||
}
|
||||
|
||||
//------------------------------------------------------
|
||||
@ -252,7 +256,6 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt
|
||||
}
|
||||
|
||||
attributedText = mutableAttributedString
|
||||
// Added this line for underlining
|
||||
setAlternateActionTextAttributes([NSAttributedString.Key.underlineStyle: NSNumber(value: NSUnderlineStyle.single.rawValue)])
|
||||
}
|
||||
|
||||
@ -346,27 +349,14 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt
|
||||
|
||||
public func setAlternateNormalTextAttributes(_ attributes: [AnyHashable: Any]?) {
|
||||
|
||||
guard let _attributedText = attributedText, let _attributes = attributes as? [NSAttributedString.Key: Any] else { return }
|
||||
let attributedString = NSMutableAttributedString(attributedString: _attributedText)
|
||||
guard let attributedText = attributedText, let attributes = attributes as? [NSAttributedString.Key: Any] else { return }
|
||||
let attributedString = NSMutableAttributedString(attributedString: attributedText)
|
||||
|
||||
if !attributedString.string.isEmpty {
|
||||
attributedString.addAttributes(_attributes, range: getFrontRange())
|
||||
attributedString.addAttributes(_attributes, range: getBackRange())
|
||||
attributedString.addAttributes(attributes, range: frontRange)
|
||||
attributedString.addAttributes(attributes, range: backRange)
|
||||
}
|
||||
attributedText = attributedString
|
||||
}
|
||||
|
||||
private func getFrontRange() -> NSRange {
|
||||
|
||||
return NSRange(location: 0, length: frontText?.count ?? 0)
|
||||
}
|
||||
|
||||
private func getBackRange() -> NSRange {
|
||||
|
||||
let textLocation: Int = (frontText?.count ?? 0) + (actionText?.count ?? 0)
|
||||
let rangeLength: Int = backText?.count ?? 0
|
||||
|
||||
return NSRange(location: textLocation, length: rangeLength)
|
||||
self.attributedText = attributedString
|
||||
}
|
||||
|
||||
@objc public func setActionTextString(_ actionText: String?) {
|
||||
@ -384,9 +374,7 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt
|
||||
frontText = actionMap?.optionalStringForKey(KeyTitlePrefix)
|
||||
actionText = actionMap?.optionalStringForKey(KeyTitle)
|
||||
backText = actionMap?.optionalStringForKey(KeyTitlePostfix)
|
||||
|
||||
actionBlock = label?.createActionBlockFrom(actionMap: actionMap, additionalData: additionalData, delegate: delegateObject)
|
||||
|
||||
actionBlock = label?.createActionBlockFrom(actionMap: actionMap, additionalData: additionalData, delegateObject: delegateObject)
|
||||
text = getTextFromStringComponents()
|
||||
setLabelAttributes()
|
||||
}
|
||||
@ -433,13 +421,11 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt
|
||||
|
||||
@available(*, deprecated)
|
||||
public convenience init(actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, actionDelegate delegate: ActionObjectDelegate?, buttonDelegate: ButtonObjectDelegate?) {
|
||||
|
||||
self.init(frontText: actionMap?.optionalStringForKey(KeyTitlePrefix), actionText: actionMap?.optionalStringForKey(KeyTitle), backText: actionMap?.optionalStringForKey(KeyTitlePostfix), actionMap: actionMap, additionalData: additionalData, actionDelegate: delegate, buttonDelegate: buttonDelegate)
|
||||
}
|
||||
|
||||
@available(*, deprecated)
|
||||
public convenience init(frontText: String?, backText: String?, actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, actionDelegate delegate: ActionObjectDelegate?, buttonDelegate: ButtonObjectDelegate?) {
|
||||
|
||||
self.init(frontText: frontText, actionText: actionMap?.optionalStringForKey(KeyTitle), backText: backText, actionMap: actionMap, additionalData: additionalData, actionDelegate: delegate, buttonDelegate: buttonDelegate)
|
||||
}
|
||||
|
||||
@ -544,7 +530,6 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt
|
||||
}
|
||||
|
||||
attributedText = mutableAttributedString
|
||||
// Added this line for underlining
|
||||
setAlternateActionTextAttributes([NSAttributedString.Key.underlineStyle: NSNumber(value: NSUnderlineStyle.single.rawValue)])
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user