merge
This commit is contained in:
commit
9316343c0e
@ -21,7 +21,7 @@
|
|||||||
01DF567021FA5AB300CC099B /* TextFieldListFormViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01DF566F21FA5AB300CC099B /* TextFieldListFormViewController.swift */; };
|
01DF567021FA5AB300CC099B /* TextFieldListFormViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01DF566F21FA5AB300CC099B /* TextFieldListFormViewController.swift */; };
|
||||||
01E569D3223FFFA500327251 /* ThreeLayerViewController.swift in Headers */ = {isa = PBXBuildFile; fileRef = D2A5146A2214905000345BFB /* ThreeLayerViewController.swift */; settings = {ATTRIBUTES = (Public, ); }; };
|
01E569D3223FFFA500327251 /* ThreeLayerViewController.swift in Headers */ = {isa = PBXBuildFile; fileRef = D2A5146A2214905000345BFB /* ThreeLayerViewController.swift */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||||
B8200E152280C4CF007245F4 /* ProgressBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8200E142280C4CF007245F4 /* ProgressBar.swift */; };
|
B8200E152280C4CF007245F4 /* ProgressBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8200E142280C4CF007245F4 /* ProgressBar.swift */; };
|
||||||
B8200E192281DC1A007245F4 /* ProgressBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8200E182281DC1A007245F4 /* ProgressBarView.swift */; };
|
B8200E192281DC1A007245F4 /* ProgressBarWithLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8200E182281DC1A007245F4 /* ProgressBarWithLabel.swift */; };
|
||||||
D206997721FB8A0B00CAE0DE /* MVMCoreUINavigationController.h in Headers */ = {isa = PBXBuildFile; fileRef = D206997521FB8A0B00CAE0DE /* MVMCoreUINavigationController.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
D206997721FB8A0B00CAE0DE /* MVMCoreUINavigationController.h in Headers */ = {isa = PBXBuildFile; fileRef = D206997521FB8A0B00CAE0DE /* MVMCoreUINavigationController.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||||
D206997821FB8A0B00CAE0DE /* MVMCoreUINavigationController.m in Sources */ = {isa = PBXBuildFile; fileRef = D206997621FB8A0B00CAE0DE /* MVMCoreUINavigationController.m */; };
|
D206997821FB8A0B00CAE0DE /* MVMCoreUINavigationController.m in Sources */ = {isa = PBXBuildFile; fileRef = D206997621FB8A0B00CAE0DE /* MVMCoreUINavigationController.m */; };
|
||||||
D20A9A5E2243D3E300ADE781 /* TwoButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20A9A5D2243D3E300ADE781 /* TwoButtonView.swift */; };
|
D20A9A5E2243D3E300ADE781 /* TwoButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20A9A5D2243D3E300ADE781 /* TwoButtonView.swift */; };
|
||||||
@ -169,6 +169,7 @@
|
|||||||
D2E1FADD2268B25E00AEFD8C /* MoleculeTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2E1FADC2268B25E00AEFD8C /* MoleculeTableViewCell.swift */; };
|
D2E1FADD2268B25E00AEFD8C /* MoleculeTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2E1FADC2268B25E00AEFD8C /* MoleculeTableViewCell.swift */; };
|
||||||
D2E1FADF2268B8E700AEFD8C /* ThreeLayerTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2E1FADE2268B8E700AEFD8C /* ThreeLayerTableViewController.swift */; };
|
D2E1FADF2268B8E700AEFD8C /* ThreeLayerTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2E1FADE2268B8E700AEFD8C /* ThreeLayerTableViewController.swift */; };
|
||||||
D2E1FAE12268E81D00AEFD8C /* MoleculeListTemplate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2E1FAE02268E81D00AEFD8C /* MoleculeListTemplate.swift */; };
|
D2E1FAE12268E81D00AEFD8C /* MoleculeListTemplate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2E1FAE02268E81D00AEFD8C /* MoleculeListTemplate.swift */; };
|
||||||
|
DB06250B2293456500B72DD3 /* LeftRightLabelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB06250A2293456500B72DD3 /* LeftRightLabelView.swift */; };
|
||||||
DBC4391822442197001AB423 /* CaretView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBC4391622442196001AB423 /* CaretView.swift */; };
|
DBC4391822442197001AB423 /* CaretView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBC4391622442196001AB423 /* CaretView.swift */; };
|
||||||
DBC4391922442197001AB423 /* DashLine.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBC4391722442197001AB423 /* DashLine.swift */; };
|
DBC4391922442197001AB423 /* DashLine.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBC4391722442197001AB423 /* DashLine.swift */; };
|
||||||
DBC4391B224421A0001AB423 /* CaretButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBC4391A224421A0001AB423 /* CaretButton.swift */; };
|
DBC4391B224421A0001AB423 /* CaretButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBC4391A224421A0001AB423 /* CaretButton.swift */; };
|
||||||
@ -190,7 +191,7 @@
|
|||||||
01DF55DF21F8FAA800CC099B /* MFTextFieldListView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MFTextFieldListView.swift; sourceTree = "<group>"; };
|
01DF55DF21F8FAA800CC099B /* MFTextFieldListView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MFTextFieldListView.swift; sourceTree = "<group>"; };
|
||||||
01DF566F21FA5AB300CC099B /* TextFieldListFormViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextFieldListFormViewController.swift; sourceTree = "<group>"; };
|
01DF566F21FA5AB300CC099B /* TextFieldListFormViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextFieldListFormViewController.swift; sourceTree = "<group>"; };
|
||||||
B8200E142280C4CF007245F4 /* ProgressBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressBar.swift; sourceTree = "<group>"; };
|
B8200E142280C4CF007245F4 /* ProgressBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressBar.swift; sourceTree = "<group>"; };
|
||||||
B8200E182281DC1A007245F4 /* ProgressBarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressBarView.swift; sourceTree = "<group>"; };
|
B8200E182281DC1A007245F4 /* ProgressBarWithLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressBarWithLabel.swift; sourceTree = "<group>"; };
|
||||||
D206997521FB8A0B00CAE0DE /* MVMCoreUINavigationController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreUINavigationController.h; sourceTree = "<group>"; };
|
D206997521FB8A0B00CAE0DE /* MVMCoreUINavigationController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreUINavigationController.h; sourceTree = "<group>"; };
|
||||||
D206997621FB8A0B00CAE0DE /* MVMCoreUINavigationController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MVMCoreUINavigationController.m; sourceTree = "<group>"; };
|
D206997621FB8A0B00CAE0DE /* MVMCoreUINavigationController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MVMCoreUINavigationController.m; sourceTree = "<group>"; };
|
||||||
D20A9A5D2243D3E300ADE781 /* TwoButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TwoButtonView.swift; sourceTree = "<group>"; };
|
D20A9A5D2243D3E300ADE781 /* TwoButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TwoButtonView.swift; sourceTree = "<group>"; };
|
||||||
@ -342,6 +343,7 @@
|
|||||||
D2E1FADC2268B25E00AEFD8C /* MoleculeTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeTableViewCell.swift; sourceTree = "<group>"; };
|
D2E1FADC2268B25E00AEFD8C /* MoleculeTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeTableViewCell.swift; sourceTree = "<group>"; };
|
||||||
D2E1FADE2268B8E700AEFD8C /* ThreeLayerTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreeLayerTableViewController.swift; sourceTree = "<group>"; };
|
D2E1FADE2268B8E700AEFD8C /* ThreeLayerTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreeLayerTableViewController.swift; sourceTree = "<group>"; };
|
||||||
D2E1FAE02268E81D00AEFD8C /* MoleculeListTemplate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeListTemplate.swift; sourceTree = "<group>"; };
|
D2E1FAE02268E81D00AEFD8C /* MoleculeListTemplate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeListTemplate.swift; sourceTree = "<group>"; };
|
||||||
|
DB06250A2293456500B72DD3 /* LeftRightLabelView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LeftRightLabelView.swift; sourceTree = "<group>"; };
|
||||||
DB891E822253FA8500022516 /* Label.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Label.swift; sourceTree = "<group>"; };
|
DB891E822253FA8500022516 /* Label.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Label.swift; sourceTree = "<group>"; };
|
||||||
DBC4391622442196001AB423 /* CaretView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CaretView.swift; sourceTree = "<group>"; };
|
DBC4391622442196001AB423 /* CaretView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CaretView.swift; sourceTree = "<group>"; };
|
||||||
DBC4391722442197001AB423 /* DashLine.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DashLine.swift; sourceTree = "<group>"; };
|
DBC4391722442197001AB423 /* DashLine.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DashLine.swift; sourceTree = "<group>"; };
|
||||||
@ -473,6 +475,7 @@
|
|||||||
01004F2F22721C3800991ECC /* RadioButton.swift */,
|
01004F2F22721C3800991ECC /* RadioButton.swift */,
|
||||||
D2E1FADC2268B25E00AEFD8C /* MoleculeTableViewCell.swift */,
|
D2E1FADC2268B25E00AEFD8C /* MoleculeTableViewCell.swift */,
|
||||||
B8200E142280C4CF007245F4 /* ProgressBar.swift */,
|
B8200E142280C4CF007245F4 /* ProgressBar.swift */,
|
||||||
|
B8200E182281DC1A007245F4 /* ProgressBarWithLabel.swift */,
|
||||||
B8200E182281DC1A007245F4 /* ProgressBarView.swift */,
|
B8200E182281DC1A007245F4 /* ProgressBarView.swift */,
|
||||||
0116A4E4228B19640094F3ED /* RadioButtonModel.swift */,
|
0116A4E4228B19640094F3ED /* RadioButtonModel.swift */,
|
||||||
);
|
);
|
||||||
@ -596,6 +599,7 @@
|
|||||||
children = (
|
children = (
|
||||||
DBC4391622442196001AB423 /* CaretView.swift */,
|
DBC4391622442196001AB423 /* CaretView.swift */,
|
||||||
DBC4391722442197001AB423 /* DashLine.swift */,
|
DBC4391722442197001AB423 /* DashLine.swift */,
|
||||||
|
DB06250A2293456500B72DD3 /* LeftRightLabelView.swift */,
|
||||||
D29DF17E21E69E2E003B2FB9 /* MFView.h */,
|
D29DF17E21E69E2E003B2FB9 /* MFView.h */,
|
||||||
D29DF17F21E69E2E003B2FB9 /* MFView.m */,
|
D29DF17F21E69E2E003B2FB9 /* MFView.m */,
|
||||||
D29DF31E21ED0CBA003B2FB9 /* LabelView.h */,
|
D29DF31E21ED0CBA003B2FB9 /* LabelView.h */,
|
||||||
@ -958,6 +962,7 @@
|
|||||||
D29DF29521E7ADB8003B2FB9 /* ProgrammaticScrollViewController.m in Sources */,
|
D29DF29521E7ADB8003B2FB9 /* ProgrammaticScrollViewController.m in Sources */,
|
||||||
D29DF16121E69996003B2FB9 /* MFViewController.m in Sources */,
|
D29DF16121E69996003B2FB9 /* MFViewController.m in Sources */,
|
||||||
D2E1FAE12268E81D00AEFD8C /* MoleculeListTemplate.swift in Sources */,
|
D2E1FAE12268E81D00AEFD8C /* MoleculeListTemplate.swift in Sources */,
|
||||||
|
DB06250B2293456500B72DD3 /* LeftRightLabelView.swift in Sources */,
|
||||||
D22D1F47220496A30077CEC0 /* MVMCoreUISwitch.m in Sources */,
|
D22D1F47220496A30077CEC0 /* MVMCoreUISwitch.m in Sources */,
|
||||||
D29DF28C21E7AC2B003B2FB9 /* ViewConstrainingView.m in Sources */,
|
D29DF28C21E7AC2B003B2FB9 /* ViewConstrainingView.m in Sources */,
|
||||||
D29DF17B21E69E1F003B2FB9 /* PrimaryButton.m in Sources */,
|
D29DF17B21E69E1F003B2FB9 /* PrimaryButton.m in Sources */,
|
||||||
@ -983,7 +988,7 @@
|
|||||||
D2A514632213643100345BFB /* MoleculeStackCenteredTemplate.swift in Sources */,
|
D2A514632213643100345BFB /* MoleculeStackCenteredTemplate.swift in Sources */,
|
||||||
D29DF32421ED0DA2003B2FB9 /* TextButtonView.m in Sources */,
|
D29DF32421ED0DA2003B2FB9 /* TextButtonView.m in Sources */,
|
||||||
D29DF29E21E7AE3B003B2FB9 /* MFStyler.m in Sources */,
|
D29DF29E21E7AE3B003B2FB9 /* MFStyler.m in Sources */,
|
||||||
B8200E192281DC1A007245F4 /* ProgressBarView.swift in Sources */,
|
B8200E192281DC1A007245F4 /* ProgressBarWithLabel.swift in Sources */,
|
||||||
D2A514592211C53C00345BFB /* MVMCoreUIMoleculeMappingObject.m in Sources */,
|
D2A514592211C53C00345BFB /* MVMCoreUIMoleculeMappingObject.m in Sources */,
|
||||||
0105618D224BBE7700E1557D /* FormValidator.swift in Sources */,
|
0105618D224BBE7700E1557D /* FormValidator.swift in Sources */,
|
||||||
D22D1F1B220341F60077CEC0 /* MVMCoreUICheckBox.m in Sources */,
|
D22D1F1B220341F60077CEC0 /* MVMCoreUICheckBox.m in Sources */,
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#import <MVMCoreUI/MFTextField.h>
|
#import <MVMCoreUI/MFTextField.h>
|
||||||
|
|
||||||
|
@class MFDigitTextBox;
|
||||||
@interface MFDigitTextField : MFTextField
|
@interface MFDigitTextField : MFTextField
|
||||||
|
|
||||||
+ (nullable instancetype)mfDigitTextFieldWithNumberOfDigits:(NSUInteger)numberOfDigits;
|
+ (nullable instancetype)mfDigitTextFieldWithNumberOfDigits:(NSUInteger)numberOfDigits;
|
||||||
@ -18,4 +19,6 @@
|
|||||||
|
|
||||||
- (void)setAsSecureTextEntry:(BOOL)secureTextEntry;
|
- (void)setAsSecureTextEntry:(BOOL)secureTextEntry;
|
||||||
|
|
||||||
|
@property (nullable, nonatomic, strong) NSArray <MFDigitTextBox *>*textFields;
|
||||||
|
//Be careful when using this directly. There's a possiblity that you may break the view.
|
||||||
@end
|
@end
|
||||||
|
|||||||
@ -29,7 +29,7 @@
|
|||||||
@property (nullable, nonatomic, weak) IBOutlet NSLayoutConstraint *messageToTextFieldPin;
|
@property (nullable, nonatomic, weak) IBOutlet NSLayoutConstraint *messageToTextFieldPin;
|
||||||
@property (nullable, nonatomic, weak) IBOutlet NSLayoutConstraint *labelToTextFieldPin;
|
@property (nullable, nonatomic, weak) IBOutlet NSLayoutConstraint *labelToTextFieldPin;
|
||||||
|
|
||||||
@property (nullable, nonatomic, strong) NSArray <MFDigitTextBox *>*textFields;
|
|
||||||
@property (nonatomic) BOOL switchedAutomatically;
|
@property (nonatomic) BOOL switchedAutomatically;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@ -576,7 +576,7 @@
|
|||||||
|
|
||||||
|
|
||||||
- (BOOL)isValidField {
|
- (BOOL)isValidField {
|
||||||
return self.valid;
|
return self.isValid;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (nullable NSString *)formFieldName {
|
- (nullable NSString *)formFieldName {
|
||||||
|
|||||||
@ -9,28 +9,49 @@
|
|||||||
|
|
||||||
import MVMCore
|
import MVMCore
|
||||||
|
|
||||||
|
public typealias ActionBlock = () -> Void
|
||||||
|
|
||||||
@objc open class Label: UILabel, MVMCoreViewProtocol, MVMCoreUIMoleculeViewProtocol, MVMCoreUIViewConstrainingProtocol {
|
|
||||||
|
@objcMembers open class Label: UILabel, MVMCoreViewProtocol, MVMCoreUIMoleculeViewProtocol, MVMCoreUIViewConstrainingProtocol, MFButtonProtocol {
|
||||||
//------------------------------------------------------
|
//------------------------------------------------------
|
||||||
// MARK: - Properties
|
// MARK: - General Properties
|
||||||
//------------------------------------------------------
|
//------------------------------------------------------
|
||||||
|
|
||||||
|
public var makeWholeViewClickable = false
|
||||||
|
|
||||||
// Set this property if you want updateView to update the font based on this standard and the size passed in.
|
/// Set this property if you want updateView to update the font based on this standard and the size passed in.
|
||||||
@objc public var standardFontSize: CGFloat = 0.0
|
public var standardFontSize: CGFloat = 0.0
|
||||||
|
|
||||||
// Set this to use a custom sizing object during updateView instead of the standard.
|
/// Set this to use a custom sizing object during updateView instead of the standard.
|
||||||
@objc public var sizeObject: MFSizeObject?
|
public var sizeObject: MFSizeObject?
|
||||||
|
public var scaleSize: NSNumber?
|
||||||
@objc public var scaleSize: NSNumber?
|
|
||||||
|
|
||||||
// Used for scaling the font in updateView.
|
// Used for scaling the font in updateView.
|
||||||
private var originalAttributedString: NSAttributedString?
|
private var originalAttributedString: NSAttributedString?
|
||||||
|
|
||||||
@objc public var hasText: Bool {
|
public var hasText: Bool {
|
||||||
guard let text = text, let attributedText = attributedText else { return false }
|
guard let text = text, let attributedText = attributedText else { return false }
|
||||||
return !text.isEmpty || !attributedText.string.isEmpty
|
return !text.isEmpty || !attributedText.string.isEmpty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------
|
||||||
|
// MARK: - Multi-Action Text
|
||||||
|
//------------------------------------------------------
|
||||||
|
|
||||||
|
public var clauses: [ActionableClause] = [] {
|
||||||
|
didSet { isUserInteractionEnabled = !clauses.isEmpty }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Used for tappable links in the text.
|
||||||
|
public struct ActionableClause {
|
||||||
|
var range: NSRange?
|
||||||
|
var actionBlock: ActionBlock?
|
||||||
|
|
||||||
|
func performAction() {
|
||||||
|
actionBlock?()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//------------------------------------------------------
|
//------------------------------------------------------
|
||||||
// MARK: - Initialization
|
// MARK: - Initialization
|
||||||
//------------------------------------------------------
|
//------------------------------------------------------
|
||||||
@ -41,6 +62,10 @@ import MVMCore
|
|||||||
numberOfLines = 0
|
numberOfLines = 0
|
||||||
lineBreakMode = .byWordWrapping
|
lineBreakMode = .byWordWrapping
|
||||||
translatesAutoresizingMaskIntoConstraints = false
|
translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
|
||||||
|
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(textLinkTapped(_:)))
|
||||||
|
tapGesture.numberOfTapsRequired = 1
|
||||||
|
addGestureRecognizer(tapGesture)
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc public init() {
|
@objc public init() {
|
||||||
@ -64,21 +89,24 @@ import MVMCore
|
|||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------
|
//------------------------------------------------------
|
||||||
// MARK: - Functions
|
// MARK: - Factory Functions
|
||||||
//------------------------------------------------------
|
//------------------------------------------------------
|
||||||
|
|
||||||
|
/// H1 -> HeadlineLarge
|
||||||
@objc public static func commonLabelH1(_ scale: Bool) -> Label {
|
@objc public static func commonLabelH1(_ scale: Bool) -> Label {
|
||||||
let label = Label.label()
|
let label = Label.label()
|
||||||
label.styleH1(scale)
|
label.styleH1(scale)
|
||||||
return label
|
return label
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// H2 -> Headline
|
||||||
@objc public static func commonLabelH2(_ scale: Bool) -> Label {
|
@objc public static func commonLabelH2(_ scale: Bool) -> Label {
|
||||||
let label = Label.label()
|
let label = Label.label()
|
||||||
label.styleH2(scale)
|
label.styleH2(scale)
|
||||||
return label
|
return label
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// H3 -> SubHead
|
||||||
@objc public static func commonLabelH3(_ scale: Bool) -> Label {
|
@objc public static func commonLabelH3(_ scale: Bool) -> Label {
|
||||||
let label = Label.label()
|
let label = Label.label()
|
||||||
label.styleH3(scale)
|
label.styleH3(scale)
|
||||||
@ -91,18 +119,21 @@ import MVMCore
|
|||||||
return label
|
return label
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// B1 -> SubTitle
|
||||||
@objc public static func commonLabelB1(_ scale: Bool) -> Label {
|
@objc public static func commonLabelB1(_ scale: Bool) -> Label {
|
||||||
let label = Label.label()
|
let label = Label.label()
|
||||||
label.styleB1(scale)
|
label.styleB1(scale)
|
||||||
return label
|
return label
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// B2 -> Body
|
||||||
@objc public static func commonLabelB2(_ scale: Bool) -> Label {
|
@objc public static func commonLabelB2(_ scale: Bool) -> Label {
|
||||||
let label = Label.label()
|
let label = Label.label()
|
||||||
label.styleB2(scale)
|
label.styleB2(scale)
|
||||||
return label
|
return label
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// B3 -> Legal
|
||||||
@objc public static func commonLabelB3(_ scale: Bool) -> Label {
|
@objc public static func commonLabelB3(_ scale: Bool) -> Label {
|
||||||
let label = Label.label()
|
let label = Label.label()
|
||||||
label.styleB3(scale)
|
label.styleB3(scale)
|
||||||
@ -142,14 +173,10 @@ import MVMCore
|
|||||||
@objc public static func setUILabel(_ label: UILabel?, withJSON json: [AnyHashable: Any]?, delegate: DelegateObject?, additionalData: [AnyHashable: Any]?) {
|
@objc public static func setUILabel(_ label: UILabel?, withJSON json: [AnyHashable: Any]?, delegate: DelegateObject?, additionalData: [AnyHashable: Any]?) {
|
||||||
|
|
||||||
guard let label = label else { return }
|
guard let label = label else { return }
|
||||||
|
label.attributedText = nil
|
||||||
label.text = json?.optionalStringForKey(KeyText)
|
label.text = json?.optionalStringForKey(KeyText)
|
||||||
|
|
||||||
setLabel(label, withHTML: json?.optionalStringForKey("html"))
|
|
||||||
|
|
||||||
if let textColorHex = json?.optionalStringForKey(KeyTextColor), !textColorHex.isEmpty {
|
setLabel(label, withHTML: json?.optionalStringForKey("html"))
|
||||||
label.textColor = UIColor.mfGet(forHex: textColorHex)
|
|
||||||
}
|
|
||||||
|
|
||||||
if let backgroundColorHex = json?.optionalStringForKey(KeyBackgroundColor), !backgroundColorHex.isEmpty {
|
if let backgroundColorHex = json?.optionalStringForKey(KeyBackgroundColor), !backgroundColorHex.isEmpty {
|
||||||
label.backgroundColor = UIColor.mfGet(forHex: backgroundColorHex)
|
label.backgroundColor = UIColor.mfGet(forHex: backgroundColorHex)
|
||||||
@ -157,52 +184,73 @@ import MVMCore
|
|||||||
|
|
||||||
label.accessibilityLabel = json?.optionalStringForKey("accessibilityText")
|
label.accessibilityLabel = json?.optionalStringForKey("accessibilityText")
|
||||||
|
|
||||||
let fontSize = json?["fontSize"] as? CGFloat
|
if let fontStyle = json?.optionalStringForKey("fontStyle") {
|
||||||
|
MFStyler.styleLabel(label, withStyle: fontStyle)
|
||||||
|
} else {
|
||||||
|
let fontSize = json?["fontSize"] as? CGFloat
|
||||||
|
|
||||||
|
if let fontName = json?.optionalStringForKey("fontName") {
|
||||||
|
label.font = MFFonts.mfFont(withName: fontName, size: fontSize ?? label.font.pointSize)
|
||||||
|
} else if let fontSize = fontSize {
|
||||||
|
label.font = label.font.withSize(fontSize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if let fontName = json?.optionalStringForKey("fontName") {
|
if let textColorHex = json?.optionalStringForKey(KeyTextColor), !textColorHex.isEmpty {
|
||||||
label.font = MFFonts.mfFont(withName: fontName, size: fontSize ?? label.font.pointSize)
|
label.textColor = UIColor.mfGet(forHex: textColorHex)
|
||||||
} else if let fontSize = fontSize {
|
|
||||||
label.font = label.font.withSize(fontSize)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let attributes = json?.arrayForKey("attributes"), let labelText = label.text {
|
if let attributes = json?.arrayForKey("attributes"), let labelText = label.text {
|
||||||
let attributedString = NSMutableAttributedString(string: labelText, attributes: [NSAttributedString.Key.font: label.font as UIFont,
|
let attributedString = NSMutableAttributedString(string: labelText, attributes: [NSAttributedString.Key.font: label.font as UIFont,
|
||||||
NSAttributedString.Key.foregroundColor: label.textColor as UIColor])
|
NSAttributedString.Key.foregroundColor: label.textColor as UIColor])
|
||||||
for case let attribute as [String: Any] in attributes {
|
for case let attribute as [String: Any] in attributes {
|
||||||
|
|
||||||
guard let attributeType = attribute.optionalStringForKey(KeyType),
|
guard let attributeType = attribute.optionalStringForKey(KeyType),
|
||||||
let location = attribute["location"] as? Int,
|
let location = attribute["location"] as? Int,
|
||||||
let length = attribute["length"] as? Int
|
let length = attribute["length"] as? Int
|
||||||
else { continue }
|
else { continue }
|
||||||
|
|
||||||
let range = NSRange(location: location, length: length)
|
let range = NSRange(location: location, length: length)
|
||||||
|
|
||||||
switch attributeType {
|
switch attributeType {
|
||||||
case "underline":
|
case "underline":
|
||||||
attributedString.addAttribute(.underlineStyle, value: NSUnderlineStyle.single.rawValue, range: range)
|
attributedString.addAttribute(.underlineStyle, value: NSUnderlineStyle.single.rawValue, range: range)
|
||||||
|
|
||||||
case "strikethrough":
|
case "strikethrough":
|
||||||
attributedString.addAttribute(.strikethroughStyle, value: NSUnderlineStyle.thick.rawValue, range: range)
|
attributedString.addAttribute(.strikethroughStyle, value: NSUnderlineStyle.thick.rawValue, range: range)
|
||||||
|
|
||||||
case "color":
|
case "color":
|
||||||
if let colorHex = attribute.optionalStringForKey(KeyTextColor), !colorHex.isEmpty {
|
if let colorHex = attribute.optionalStringForKey(KeyTextColor), !colorHex.isEmpty {
|
||||||
attributedString.removeAttribute(.foregroundColor, range: range)
|
attributedString.removeAttribute(.foregroundColor, range: range)
|
||||||
attributedString.addAttribute(.foregroundColor, value: UIColor.mfGet(forHex: colorHex), range: range)
|
attributedString.addAttribute(.foregroundColor, value: UIColor.mfGet(forHex: colorHex), range: range)
|
||||||
}
|
}
|
||||||
case "font":
|
case "font":
|
||||||
let fontSize = attribute["size"] as? CGFloat
|
if let fontStyle = attribute.optionalStringForKey("style") {
|
||||||
var font: UIFont?
|
let styles = MFStyler.styleGetAttributedString("0", withStyle: fontStyle)
|
||||||
|
|
||||||
if let fontName = attribute.optionalStringForKey("name") {
|
|
||||||
font = MFFonts.mfFont(withName: fontName, size: fontSize ?? label.font.pointSize)
|
|
||||||
} else if let fontSize = fontSize {
|
|
||||||
font = label.font.withSize(fontSize)
|
|
||||||
}
|
|
||||||
|
|
||||||
if let font = font {
|
|
||||||
attributedString.removeAttribute(.font, range: range)
|
attributedString.removeAttribute(.font, range: range)
|
||||||
attributedString.addAttribute(.font, value: font, range: range)
|
attributedString.removeAttribute(.foregroundColor, range: range)
|
||||||
|
attributedString.addAttributes(styles.attributes(at: 0, effectiveRange: nil), range: range)
|
||||||
|
} else {
|
||||||
|
let fontSize = attribute["size"] as? CGFloat
|
||||||
|
var font: UIFont?
|
||||||
|
|
||||||
|
if let fontName = attribute.optionalStringForKey("name") {
|
||||||
|
font = MFFonts.mfFont(withName: fontName, size: fontSize ?? label.font.pointSize)
|
||||||
|
} else if let fontSize = fontSize {
|
||||||
|
font = label.font.withSize(fontSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
if let font = font {
|
||||||
|
attributedString.removeAttribute(.font, range: range)
|
||||||
|
attributedString.addAttribute(.font, value: font, range: range)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
case "action":
|
||||||
|
guard let actionLabel = label as? Label else { continue }
|
||||||
|
|
||||||
|
actionLabel.addTappableLinkAttribute(range: range,
|
||||||
|
actionMap: json,
|
||||||
|
additionalData: additionalData,
|
||||||
|
delegateObject: delegate)
|
||||||
default:
|
default:
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -211,6 +259,8 @@ import MVMCore
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//------------------------------------------------------
|
//------------------------------------------------------
|
||||||
// MARK: - Methods
|
// MARK: - Methods
|
||||||
//------------------------------------------------------
|
//------------------------------------------------------
|
||||||
@ -290,10 +340,10 @@ import MVMCore
|
|||||||
standardFontSize = 0
|
standardFontSize = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
//------------------------------------------------------
|
|
||||||
// MARK: - Atomization
|
// MARK: - Atomization
|
||||||
//------------------------------------------------------
|
extension Label {
|
||||||
|
|
||||||
public func reset() {
|
public func reset() {
|
||||||
text = nil
|
text = nil
|
||||||
@ -303,16 +353,17 @@ import MVMCore
|
|||||||
}
|
}
|
||||||
|
|
||||||
@objc public func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
|
@objc public func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
|
||||||
|
clauses = []
|
||||||
Label.setUILabel(self, withJSON: json, delegate: delegateObject, additionalData: additionalData)
|
Label.setUILabel(self, withJSON: json, delegate: delegateObject, additionalData: additionalData)
|
||||||
originalAttributedString = attributedText
|
originalAttributedString = attributedText
|
||||||
}
|
}
|
||||||
|
|
||||||
public func setAsMolecule() {
|
public func setAsMolecule() {
|
||||||
setContentHuggingPriority(.required, for: .vertical)
|
styleB2(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func needsToBeConstrained() -> Bool {
|
public func needsToBeConstrained() -> Bool {
|
||||||
return true;
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
public func alignment() -> UIStackView.Alignment {
|
public func alignment() -> UIStackView.Alignment {
|
||||||
@ -320,6 +371,111 @@ import MVMCore
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: - Multi-Action Functionality
|
||||||
extension Label {
|
extension Label {
|
||||||
|
|
||||||
|
/// 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 { [weak self] in
|
||||||
|
if let wSelf = self, (delegateObject as? MVMCoreUIDelegateObject)?.buttonDelegate?.button?(wSelf, shouldPerformActionWithMap: actionMap, additionalData: additionalData) ?? true {
|
||||||
|
MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegateObject: delegateObject)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Provides an actionable range of text.
|
||||||
|
|
||||||
|
- Attention: This method expects text to be set first. Otherwise, it will do nothing.
|
||||||
|
- Parameters:
|
||||||
|
- range: The range of text to be tapped.
|
||||||
|
- actionBlock: The code triggered when tapping the range of text.
|
||||||
|
*/
|
||||||
|
@objc public func addTappableLinkAttribute(range: NSRange, actionBlock: @escaping ActionBlock) {
|
||||||
|
|
||||||
|
setDefaultAttributes(range: range)
|
||||||
|
clauses.append(ActionableClause(range: range, actionBlock: actionBlock))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Provides an actionable range of text.
|
||||||
|
|
||||||
|
- Attention: This method expects text to be set first. Otherwise, it will do nothing.
|
||||||
|
- Parameters:
|
||||||
|
- range: The range of text to be tapped.
|
||||||
|
- actionMap:
|
||||||
|
- delegate:
|
||||||
|
- additionalData:
|
||||||
|
*/
|
||||||
|
@objc public func addTappableLinkAttribute(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)))
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc private func textLinkTapped(_ gesture: UITapGestureRecognizer) {
|
||||||
|
|
||||||
|
for clause in clauses {
|
||||||
|
if let range = clause.range, gesture.didTapAttributedTextInLabel(self, inRange: range) {
|
||||||
|
clause.performAction()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: -
|
||||||
|
extension UITapGestureRecognizer {
|
||||||
|
|
||||||
|
func didTapAttributedTextInLabel(_ label: Label, inRange targetRange: NSRange) -> Bool {
|
||||||
|
|
||||||
|
if label.makeWholeViewClickable {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
guard let attributedText = label.attributedText else { return false }
|
||||||
|
|
||||||
|
let layoutManager = NSLayoutManager()
|
||||||
|
let textContainer = NSTextContainer(size: .zero)
|
||||||
|
let textStorage = NSTextStorage(attributedString: attributedText)
|
||||||
|
|
||||||
|
layoutManager.addTextContainer(textContainer)
|
||||||
|
textStorage.addLayoutManager(layoutManager)
|
||||||
|
|
||||||
|
textContainer.lineFragmentPadding = 0.0
|
||||||
|
textContainer.lineBreakMode = label.lineBreakMode
|
||||||
|
textContainer.maximumNumberOfLines = label.numberOfLines
|
||||||
|
textContainer.size = label.bounds.size
|
||||||
|
|
||||||
|
let indexOfCharacter = layoutManager.characterIndex(for: location(in: label), in: textContainer, fractionOfDistanceBetweenInsertionPoints: nil)
|
||||||
|
|
||||||
|
return NSLocationInRange(indexOfCharacter, targetRange)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,9 +15,4 @@
|
|||||||
// Customize the label.
|
// Customize the label.
|
||||||
@property (nullable, weak, nonatomic) Label *label;
|
@property (nullable, weak, nonatomic) Label *label;
|
||||||
|
|
||||||
// Change the alignment of the label
|
|
||||||
- (void)alignLeft;
|
|
||||||
- (void)alignCenter;
|
|
||||||
- (void)alignRight;
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@ -11,11 +11,6 @@
|
|||||||
#import <MVMCoreUI/MVMCoreUI-Swift.h>
|
#import <MVMCoreUI/MVMCoreUI-Swift.h>
|
||||||
@interface LabelView ()
|
@interface LabelView ()
|
||||||
|
|
||||||
// Change to customize.
|
|
||||||
@property (strong, nonatomic) NSLayoutConstraint *alignCenterPin;
|
|
||||||
@property (strong, nonatomic) NSLayoutConstraint *alignCenterLeftPin;
|
|
||||||
@property (strong, nonatomic) NSLayoutConstraint *alignCenterRightPin;
|
|
||||||
|
|
||||||
// Sets up the view.
|
// Sets up the view.
|
||||||
- (void)setupView;
|
- (void)setupView;
|
||||||
|
|
||||||
@ -36,39 +31,7 @@
|
|||||||
Label *label = [Label commonLabelB2:YES];
|
Label *label = [Label commonLabelB2:YES];
|
||||||
[self addSubview:label];
|
[self addSubview:label];
|
||||||
self.label = label;
|
self.label = label;
|
||||||
|
[self pinViewToSuperView:label];
|
||||||
// Align left and right constants.
|
|
||||||
NSLayoutConstraint *leftPin = [NSLayoutConstraint constraintWithItem:label attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeft multiplier:1.0 constant:0];
|
|
||||||
self.leftPin = leftPin;
|
|
||||||
leftPin.active = YES;
|
|
||||||
|
|
||||||
NSLayoutConstraint *topPin = [NSLayoutConstraint constraintWithItem:label attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTop multiplier:1.0 constant:0];
|
|
||||||
topPin.priority = 999;
|
|
||||||
self.topPin = topPin;
|
|
||||||
topPin.active = YES;
|
|
||||||
|
|
||||||
NSLayoutConstraint *bottomPin = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:label attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0];
|
|
||||||
self.bottomPin = bottomPin;
|
|
||||||
bottomPin.active = YES;
|
|
||||||
|
|
||||||
NSLayoutConstraint *rightPin = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:label attribute:NSLayoutAttributeRight multiplier:1.0 constant:0];
|
|
||||||
rightPin.priority = 999;
|
|
||||||
self.rightPin = rightPin;
|
|
||||||
rightPin.active = YES;
|
|
||||||
|
|
||||||
// Center alignments
|
|
||||||
NSLayoutConstraint *alignCenter = [NSLayoutConstraint constraintWithItem:label attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0];
|
|
||||||
self.alignCenterPin = alignCenter;
|
|
||||||
alignCenter.active = YES;
|
|
||||||
|
|
||||||
NSLayoutConstraint *centerLeftPin = [NSLayoutConstraint constraintWithItem:label attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:self attribute:NSLayoutAttributeLeft multiplier:1.0 constant:0];
|
|
||||||
self.alignCenterLeftPin = centerLeftPin;
|
|
||||||
centerLeftPin.active = YES;
|
|
||||||
|
|
||||||
NSLayoutConstraint *centerRightPin = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:label attribute:NSLayoutAttributeRight multiplier:1.0 constant:0];
|
|
||||||
self.alignCenterRightPin = centerRightPin;
|
|
||||||
centerRightPin.active = YES;
|
|
||||||
|
|
||||||
[self alignLeft];
|
[self alignLeft];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -79,42 +42,20 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void)alignLeft {
|
- (void)alignLeft {
|
||||||
self.alignCenterPin.active = NO;
|
[super alignLeft];
|
||||||
self.alignCenterLeftPin.active = NO;
|
|
||||||
self.alignCenterRightPin.active = NO;
|
|
||||||
self.leftPin.active = YES;
|
|
||||||
self.rightPin.active = YES;
|
|
||||||
self.label.textAlignment = NSTextAlignmentLeft;
|
self.label.textAlignment = NSTextAlignmentLeft;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)alignCenter {
|
- (void)alignCenterHorizontal {
|
||||||
self.alignCenterPin.active = YES;
|
[super alignCenterHorizontal];
|
||||||
self.alignCenterLeftPin.active = YES;
|
|
||||||
self.alignCenterRightPin.active = YES;
|
|
||||||
self.leftPin.active = NO;
|
|
||||||
self.rightPin.active = NO;
|
|
||||||
self.label.textAlignment = NSTextAlignmentCenter;
|
self.label.textAlignment = NSTextAlignmentCenter;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)alignRight {
|
- (void)alignRight {
|
||||||
self.alignCenterPin.active = NO;
|
[super alignRight];
|
||||||
self.alignCenterLeftPin.active = NO;
|
|
||||||
self.alignCenterRightPin.active = NO;
|
|
||||||
self.leftPin.active = YES;
|
|
||||||
self.rightPin.active = YES;
|
|
||||||
self.label.textAlignment = NSTextAlignmentRight;
|
self.label.textAlignment = NSTextAlignmentRight;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setLeftPinConstant:(CGFloat)constant {
|
|
||||||
[super setLeftPinConstant:constant];
|
|
||||||
self.alignCenterLeftPin.constant = constant;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setRightPinConstant:(CGFloat)constant {
|
|
||||||
[super setRightPinConstant:constant];
|
|
||||||
self.alignCenterRightPin.constant = constant;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)resetConstraints {
|
- (void)resetConstraints {
|
||||||
[super resetConstraints];
|
[super resetConstraints];
|
||||||
[self alignLeft];
|
[self alignLeft];
|
||||||
|
|||||||
@ -9,25 +9,22 @@
|
|||||||
|
|
||||||
import MVMCore
|
import MVMCore
|
||||||
|
|
||||||
public typealias ActionBlock = () -> Void
|
|
||||||
private typealias ActionableStringTuple = (front: String?, action: String?, end: String?)
|
|
||||||
public typealias ActionObjectDelegate = NSObjectProtocol & MVMCoreActionDelegateProtocol
|
public typealias ActionObjectDelegate = NSObjectProtocol & MVMCoreActionDelegateProtocol
|
||||||
public typealias ButtonObjectDelegate = NSObjectProtocol & ButtonDelegateProtocol
|
public typealias ButtonObjectDelegate = NSObjectProtocol & ButtonDelegateProtocol
|
||||||
public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProtocol & MVMCoreLoadDelegateProtocol & MVMCorePresentationDelegateProtocol & NSObjectProtocol
|
public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProtocol & MVMCoreLoadDelegateProtocol & MVMCorePresentationDelegateProtocol & NSObjectProtocol
|
||||||
|
|
||||||
|
|
||||||
@objcMembers open class LabelWithInternalButton: UIControl, MVMCoreViewProtocol, MFButtonProtocol {
|
@available(*, deprecated, message: "Use Label instead.")
|
||||||
|
@objcMembers open class LabelWithInternalButton: UIControl, MVMCoreViewProtocol, MFButtonProtocol, MVMCoreUIMoleculeViewProtocol {
|
||||||
//------------------------------------------------------
|
//------------------------------------------------------
|
||||||
// MARK: - Properties
|
// MARK: - Properties
|
||||||
//------------------------------------------------------
|
//------------------------------------------------------
|
||||||
|
|
||||||
public var actionBlock: ActionBlock?
|
|
||||||
public weak var label: Label?
|
public weak var label: Label?
|
||||||
|
|
||||||
public var attributedText: NSAttributedString? {
|
public var attributedText: NSAttributedString? {
|
||||||
willSet(newAttributedText) {
|
willSet(newAttributedText) {
|
||||||
if let newAttribText = newAttributedText {
|
if let newAttribText = newAttributedText {
|
||||||
|
|
||||||
let mutableAttributedText = NSMutableAttributedString(attributedString: newAttribText)
|
let mutableAttributedText = NSMutableAttributedString(attributedString: newAttribText)
|
||||||
let paragraphStyle = NSMutableParagraphStyle()
|
let paragraphStyle = NSMutableParagraphStyle()
|
||||||
paragraphStyle.lineSpacing = CGFloat(LabelWithInternalButtonLineSpace)
|
paragraphStyle.lineSpacing = CGFloat(LabelWithInternalButtonLineSpace)
|
||||||
@ -62,16 +59,34 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public var actionBlock: ActionBlock? {
|
||||||
|
willSet(newActionBlock) {
|
||||||
|
if newActionBlock == nil {
|
||||||
|
label?.clearActionableClauses()
|
||||||
|
} else {
|
||||||
|
label?.clauses = [Label.ActionableClause(range: actionRange, actionBlock: newActionBlock)]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var frontRange: NSRange {
|
||||||
|
return NSRange(location: 0, length: frontText?.count ?? 0)
|
||||||
|
}
|
||||||
|
|
||||||
private var actionRange: NSRange {
|
private var actionRange: NSRange {
|
||||||
return NSRange(location: frontText?.count ?? 0, length: actionText?.count ?? 0)
|
return NSRange(location: frontText?.count ?? 0, length: actionText?.count ?? 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
public var makeWholeViewClickable = false
|
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 }
|
||||||
|
}
|
||||||
|
|
||||||
override open var isEnabled: Bool {
|
override open var isEnabled: Bool {
|
||||||
didSet {
|
didSet { alpha = isEnabled ? 1 : DisableOppacity }
|
||||||
alpha = isEnabled ? 1 : DisableOppacity
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public var frontText: String?
|
public var frontText: String?
|
||||||
@ -81,9 +96,7 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt
|
|||||||
private var internalText: String = ""
|
private var internalText: String = ""
|
||||||
|
|
||||||
public var text: String? {
|
public var text: String? {
|
||||||
get {
|
get { return internalText }
|
||||||
return internalText
|
|
||||||
}
|
|
||||||
set {
|
set {
|
||||||
guard let text = newValue else { return }
|
guard let text = newValue else { return }
|
||||||
internalText = text
|
internalText = text
|
||||||
@ -101,117 +114,92 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt
|
|||||||
|
|
||||||
public init() {
|
public init() {
|
||||||
super.init(frame: .zero)
|
super.init(frame: .zero)
|
||||||
setup()
|
createLabel()
|
||||||
|
setLabelAttributes()
|
||||||
}
|
}
|
||||||
|
|
||||||
required public init?(coder: NSCoder) {
|
required public init?(coder: NSCoder) {
|
||||||
super.init(coder: coder)
|
super.init(coder: coder)
|
||||||
setup()
|
createLabel()
|
||||||
|
setLabelAttributes()
|
||||||
}
|
}
|
||||||
|
|
||||||
override public init(frame: CGRect) {
|
override public init(frame: CGRect) {
|
||||||
super.init(frame: frame)
|
super.init(frame: frame)
|
||||||
setup()
|
createLabel()
|
||||||
|
setLabelAttributes()
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - legacy
|
// Legacy
|
||||||
public init(frontText: String?, actionText: String?, backText: String?, actionBlock block: ActionBlock?) {
|
public init(frontText: String?, actionText: String?, backText: String?, actionBlock block: ActionBlock?) {
|
||||||
super.init(frame: .zero)
|
super.init(frame: .zero)
|
||||||
|
|
||||||
|
createLabel()
|
||||||
self.frontText = frontText
|
self.frontText = frontText
|
||||||
self.actionText = actionText
|
self.actionText = actionText
|
||||||
self.backText = backText
|
self.backText = backText
|
||||||
actionBlock = block
|
|
||||||
text = getTextFromStringComponents()
|
text = getTextFromStringComponents()
|
||||||
setup()
|
actionBlock = block
|
||||||
|
setLabelAttributes()
|
||||||
}
|
}
|
||||||
|
|
||||||
public convenience init(actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) {
|
public convenience init(actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) {
|
||||||
self.init(frontText: actionMap?.optionalStringForKey(KeyTitlePrefix),
|
self.init(frontText: actionMap?.optionalStringForKey(KeyTitlePrefix), actionText: actionMap?.optionalStringForKey(KeyTitle), backText: actionMap?.optionalStringForKey(KeyTitlePostfix), actionMap: actionMap, additionalData: additionalData, delegateObject: delegateObject)
|
||||||
actionText: actionMap?.optionalStringForKey(KeyTitle),
|
|
||||||
backText: actionMap?.optionalStringForKey(KeyTitlePostfix),
|
|
||||||
actionMap: actionMap, additionalData: additionalData,
|
|
||||||
delegateObject: delegateObject)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public convenience init(frontText: String?, backText: String?, actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) {
|
public convenience init(frontText: String?, backText: String?, actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) {
|
||||||
self.init(frontText: frontText,
|
self.init(frontText: frontText, actionText: actionMap?.optionalStringForKey(KeyTitle), backText: backText, actionMap: actionMap, additionalData: additionalData, delegateObject: delegateObject)
|
||||||
actionText: actionMap?.optionalStringForKey(KeyTitle),
|
|
||||||
backText: backText,
|
|
||||||
actionMap: actionMap,
|
|
||||||
additionalData: additionalData,
|
|
||||||
delegateObject: delegateObject)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(frontText: String?, actionText: String?, backText: String?, actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) {
|
public init(frontText: String?, actionText: String?, backText: String?, actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) {
|
||||||
super.init(frame: CGRect.zero)
|
super.init(frame: .zero)
|
||||||
|
|
||||||
setFrontText(frontText, actionText: actionText, actionMap: actionMap, backText: backText, additionalData: additionalData, delegateObject: delegateObject)
|
setFrontText(frontText, actionText: actionText, actionMap: actionMap, backText: backText, additionalData: additionalData, delegateObject: delegateObject)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convenience Initializer which assumes that the clickable text will be embedded in curly braces {}.
|
// Convenience Initializer which assumes that the clickable text will be embedded in curly braces {}.
|
||||||
public convenience init(clickableTextEmbeddedInCurlyBraces fullText: String?, actionMapForClickableText actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) {
|
public convenience init(clickableTextEmbeddedInCurlyBraces fullText: String?, actionMapForClickableText actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) {
|
||||||
self.init(text: fullText,
|
self.init(text: fullText, startTag: "{", endTag: "}", actionMap: actionMap, additionalData: additionalData, delegateObject: delegateObject)
|
||||||
startTag: "{",
|
|
||||||
endTag: "}",
|
|
||||||
actionMap: actionMap,
|
|
||||||
additionalData: additionalData,
|
|
||||||
delegateObject: delegateObject)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(text fullText: String?, startTag: String?, endTag: String?, actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) {
|
public init(text fullText: String?, startTag: String?, endTag: String?, actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) {
|
||||||
super.init(frame: CGRect.zero)
|
super.init(frame: .zero)
|
||||||
|
|
||||||
setText(fullText, startTag: startTag, endTag: endTag)
|
setText(fullText, startTag: startTag, endTag: endTag)
|
||||||
|
actionBlock = label?.createActionBlockFrom(actionMap: actionMap, additionalData: additionalData, delegateObject: delegateObject)
|
||||||
actionBlock = {
|
|
||||||
MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegateObject: delegateObject)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------
|
//------------------------------------------------------
|
||||||
// MARK: - Configuration
|
// MARK: - Configuration
|
||||||
//------------------------------------------------------
|
//------------------------------------------------------
|
||||||
|
|
||||||
private func setup() {
|
/// Creates the Label that will be interacted with.
|
||||||
|
private func createLabel() {
|
||||||
|
|
||||||
if self.label == nil {
|
if self.label == nil {
|
||||||
let label = Label(frame: CGRect.zero)
|
let label = Label(frame: .zero)
|
||||||
|
|
||||||
backgroundColor = .clear
|
|
||||||
label.isUserInteractionEnabled = false
|
|
||||||
label.setContentCompressionResistancePriority(.required, for: .vertical)
|
label.setContentCompressionResistancePriority(.required, for: .vertical)
|
||||||
addSubview(label)
|
addSubview(label)
|
||||||
NSLayoutConstraint.activate(NSLayoutConstraint.constraints(withVisualFormat: "H:|-0-[label]-0-|", options: .directionLeadingToTrailing, metrics: nil, views: ["label": label]))
|
NSLayoutConstraint.constraintPinSubview(label, pinTop: true, pinBottom: true, pinLeft: true, pinRight: true)
|
||||||
NSLayoutConstraint.activate(NSLayoutConstraint.constraints(withVisualFormat: "V:|-0-[label]-0-|", options: .directionLeadingToTrailing, metrics: nil, views: ["label": label]))
|
|
||||||
|
|
||||||
self.label = label
|
self.label = label
|
||||||
label.sizeToFit()
|
label.sizeToFit()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets up label. Best to call sometime after setting the text.
|
||||||
|
private func setLabelAttributes() {
|
||||||
|
|
||||||
// Adding the underline
|
// Adding the underline
|
||||||
setAlternateActionTextAttributes([NSAttributedString.Key.underlineStyle: NSNumber(value: NSUnderlineStyle.single.rawValue)])
|
setAlternateActionTextAttributes([NSAttributedString.Key.underlineStyle: NSNumber(value: NSUnderlineStyle.single.rawValue)])
|
||||||
|
|
||||||
self.label?.attributedText = attributedText
|
label?.attributedText = attributedText
|
||||||
self.label?.accessibilityTraits = .button
|
label?.accessibilityTraits = actionText?.isEmpty ?? true ? .staticText : .button
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc public func setActionMap(_ actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) {
|
@objc public func setActionMap(_ actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) {
|
||||||
|
|
||||||
weak var weakSelf: LabelWithInternalButton? = self
|
actionBlock = label?.createActionBlockFrom(actionMap: actionMap, additionalData: additionalData, delegateObject: delegateObject)
|
||||||
weak var weakButtonDelegate: ButtonDelegateProtocol? = (delegateObject as? MVMCoreUIDelegateObject)?.buttonDelegate
|
|
||||||
|
|
||||||
actionBlock = {
|
|
||||||
var performAction = true
|
|
||||||
|
|
||||||
if let wSelf = weakSelf, let wButtonDelegate = weakButtonDelegate, wButtonDelegate.responds(to: #selector(ButtonObjectDelegate.button(_:shouldPerformActionWithMap:additionalData:))) {
|
|
||||||
performAction = wButtonDelegate.button?(wSelf, shouldPerformActionWithMap: actionMap, additionalData: additionalData) ?? false
|
|
||||||
}
|
|
||||||
|
|
||||||
if performAction {
|
|
||||||
MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegateObject: delegateObject)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------
|
//------------------------------------------------------
|
||||||
@ -220,12 +208,13 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt
|
|||||||
|
|
||||||
@objc public func setFrontText(_ frontText: String?, actionText: String?, actionMap: [AnyHashable: Any]?, backText: String?, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) {
|
@objc public func setFrontText(_ frontText: String?, actionText: String?, actionMap: [AnyHashable: Any]?, backText: String?, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) {
|
||||||
|
|
||||||
|
createLabel()
|
||||||
self.frontText = frontText
|
self.frontText = frontText
|
||||||
setActionMap(actionMap, additionalData: additionalData, delegateObject: delegateObject)
|
|
||||||
self.actionText = actionText
|
self.actionText = actionText
|
||||||
self.backText = backText
|
self.backText = backText
|
||||||
text = getTextFromStringComponents()
|
text = getTextFromStringComponents()
|
||||||
setup()
|
setActionMap(actionMap, additionalData: additionalData, delegateObject: delegateObject)
|
||||||
|
setLabelAttributes()
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc public func setFrontText(_ frontText: String?, actionMap: [AnyHashable: Any]?, backText: String?, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) {
|
@objc public func setFrontText(_ frontText: String?, actionMap: [AnyHashable: Any]?, backText: String?, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) {
|
||||||
@ -244,10 +233,8 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let b2Font = MFStyler.fontB2(),
|
if let b2Font = MFStyler.fontB2(),
|
||||||
let actions = actionMap,
|
let actions = actionMap, actions.keys.count > 0,
|
||||||
actions.keys.count > 0,
|
let actionString = actions.optionalStringForKey(KeyTitle), !actionString.isEmpty {
|
||||||
let actionString = actions.optionalStringForKey(KeyTitle),
|
|
||||||
!actionString.isEmpty {
|
|
||||||
|
|
||||||
let actionStringOnLine = actionString + (addNewLine ? "\n" : " ")
|
let actionStringOnLine = actionString + (addNewLine ? "\n" : " ")
|
||||||
actionText = actionStringOnLine
|
actionText = actionStringOnLine
|
||||||
@ -264,7 +251,6 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt
|
|||||||
}
|
}
|
||||||
|
|
||||||
attributedText = mutableAttributedString
|
attributedText = mutableAttributedString
|
||||||
// Added this line for underlining
|
|
||||||
setAlternateActionTextAttributes([NSAttributedString.Key.underlineStyle: NSNumber(value: NSUnderlineStyle.single.rawValue)])
|
setAlternateActionTextAttributes([NSAttributedString.Key.underlineStyle: NSNumber(value: NSUnderlineStyle.single.rawValue)])
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -276,51 +262,6 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt
|
|||||||
label?.attributedText = attributedText
|
label?.attributedText = attributedText
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------
|
|
||||||
// MARK: - UIControl Override
|
|
||||||
//------------------------------------------------------
|
|
||||||
|
|
||||||
override open func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
|
|
||||||
|
|
||||||
if areTouches(inActionString: touches) {
|
|
||||||
sendActions(for: .touchUpInside)
|
|
||||||
if let action = actionBlock {
|
|
||||||
action()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
sendActions(for: .touchUpOutside)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func areTouches(inActionString touches: Set<UITouch>?) -> Bool {
|
|
||||||
|
|
||||||
if UIAccessibility.isVoiceOverRunning || makeWholeViewClickable {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
let location: CGPoint? = touches?.first?.location(in: label)
|
|
||||||
let actionString = actionText
|
|
||||||
let index: Int = actionRange.location
|
|
||||||
let rangeArray = getRangeArrayOfWords(in: actionString, withInitalIndex: index)
|
|
||||||
let rectArray = getRectArray(fromRangeArray: rangeArray)
|
|
||||||
var result = false
|
|
||||||
|
|
||||||
for aValueOfRect in rectArray as? [NSValue] ?? [] {
|
|
||||||
let wordRect: CGRect = aValueOfRect.cgRectValue
|
|
||||||
|
|
||||||
if let position = location, wordRect.contains(position) {
|
|
||||||
result = true
|
|
||||||
break
|
|
||||||
} else if wordRect.origin.x == 0 && wordRect.origin.y == 0 && wordRect.size.height == 0 && wordRect.size.width == 0 {
|
|
||||||
// Incase word rect is not found for any reason, make the whole label to be clicable to avoid non functioning link in production.
|
|
||||||
result = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------------------------------
|
//------------------------------------------------------
|
||||||
// MARK: - Helper
|
// MARK: - Helper
|
||||||
//------------------------------------------------------
|
//------------------------------------------------------
|
||||||
@ -338,40 +279,6 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt
|
|||||||
return "\(frontText ?? "")\(actionText ?? "")\(backText ?? "")"
|
return "\(frontText ?? "")\(actionText ?? "")\(backText ?? "")"
|
||||||
}
|
}
|
||||||
|
|
||||||
private func getRangeArrayOfWords(in string: String?, withInitalIndex index: Int) -> [Any]? {
|
|
||||||
|
|
||||||
var index = index
|
|
||||||
let words = string?.components(separatedBy: " ")
|
|
||||||
var rangeArray = [AnyHashable]()
|
|
||||||
|
|
||||||
for subString in words ?? [] {
|
|
||||||
let finalSubString = subString + " "
|
|
||||||
let wordIndex: Int = index
|
|
||||||
let length: Int = finalSubString.count
|
|
||||||
let subStringRange = NSRange(location: wordIndex, length: length)
|
|
||||||
let rangeValue = NSValue(range: subStringRange)
|
|
||||||
rangeArray.append(rangeValue)
|
|
||||||
index += length
|
|
||||||
}
|
|
||||||
|
|
||||||
return rangeArray
|
|
||||||
}
|
|
||||||
|
|
||||||
private func getRectArray(fromRangeArray rangeArray: [Any]?) -> [Any]? {
|
|
||||||
|
|
||||||
var rectArray = [AnyHashable]()
|
|
||||||
|
|
||||||
for aValueOfRange in rangeArray as? [NSValue] ?? [] {
|
|
||||||
let wordRange: NSRange = aValueOfRange.rangeValue
|
|
||||||
if let rect: CGRect = label?.boundingRect(forCharacterRange: wordRange) {
|
|
||||||
let rectValue = NSValue(cgRect: rect)
|
|
||||||
rectArray.append(rectValue)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return rectArray
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc public func setCurlyBracedText(_ text: String) {
|
@objc public func setCurlyBracedText(_ text: String) {
|
||||||
|
|
||||||
setText(text, startTag: "{", endTag: "}")
|
setText(text, startTag: "{", endTag: "}")
|
||||||
@ -379,47 +286,24 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt
|
|||||||
|
|
||||||
private func setText(_ text: String?, startTag: String?, endTag: String?) {
|
private func setText(_ text: String?, startTag: String?, endTag: String?) {
|
||||||
|
|
||||||
let actionableTuple: ActionableStringTuple = rangeOfText(text, startTag: startTag, endTag: endTag)
|
createLabel()
|
||||||
|
frontText = text
|
||||||
|
|
||||||
if let text = text,
|
if let text = text {
|
||||||
let leftTag = startTag,
|
var initialSegments = [String]()
|
||||||
text.contains(leftTag),
|
if let leftTag = startTag, text.contains(leftTag) {
|
||||||
let rightTag = endTag,
|
initialSegments = text.components(separatedBy: leftTag)
|
||||||
text.contains(rightTag),
|
frontText = initialSegments[0].trimmingCharacters(in: .whitespaces)
|
||||||
let front = actionableTuple.front,
|
|
||||||
let middle = actionableTuple.action,
|
if let rightTag = endTag, text.contains(rightTag) {
|
||||||
let end = actionableTuple.end {
|
let secondPart = initialSegments[1].components(separatedBy: rightTag)
|
||||||
|
actionText = secondPart[0].trimmingCharacters(in: .whitespaces)
|
||||||
frontText = front.trimmingCharacters(in: .whitespaces)
|
backText = secondPart[1].trimmingCharacters(in: .whitespaces)
|
||||||
actionText = middle.trimmingCharacters(in: .whitespaces)
|
}
|
||||||
backText = end.trimmingCharacters(in: .whitespaces)
|
|
||||||
} else {
|
|
||||||
frontText = text
|
|
||||||
}
|
|
||||||
|
|
||||||
self.text = getTextFromStringComponents()
|
|
||||||
setup()
|
|
||||||
}
|
|
||||||
|
|
||||||
private func rangeOfText(_ text: String?, startTag: String?, endTag: String?) -> ActionableStringTuple {
|
|
||||||
|
|
||||||
var actionableTuple: ActionableStringTuple = (front: nil, action: nil, end: nil)
|
|
||||||
|
|
||||||
guard let text = text else { return actionableTuple }
|
|
||||||
|
|
||||||
if let leftTag = startTag, text.contains(leftTag) {
|
|
||||||
|
|
||||||
let firstHalf = text.components(separatedBy: leftTag)
|
|
||||||
actionableTuple.front = firstHalf.first
|
|
||||||
|
|
||||||
if let rightTag = endTag, text.contains(rightTag) {
|
|
||||||
let secondHalf = firstHalf[1].components(separatedBy: rightTag)
|
|
||||||
actionableTuple.action = secondHalf[0]
|
|
||||||
actionableTuple.end = secondHalf[1]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
self.text = getTextFromStringComponents()
|
||||||
return actionableTuple
|
setLabelAttributes()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset the text and action map
|
// Reset the text and action map
|
||||||
@ -459,49 +343,34 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt
|
|||||||
|
|
||||||
public func setAlternateNormalTextAttributes(_ attributes: [AnyHashable: Any]?) {
|
public func setAlternateNormalTextAttributes(_ attributes: [AnyHashable: Any]?) {
|
||||||
|
|
||||||
guard let _attributedText = attributedText, let _attributes = attributes as? [NSAttributedString.Key: Any] else { return }
|
guard let attributedText = attributedText, let attributes = attributes as? [NSAttributedString.Key: Any] else { return }
|
||||||
let attributedString = NSMutableAttributedString(attributedString: _attributedText)
|
let attributedString = NSMutableAttributedString(attributedString: attributedText)
|
||||||
|
|
||||||
if !attributedString.string.isEmpty {
|
if !attributedString.string.isEmpty {
|
||||||
attributedString.addAttributes(_attributes, range: getFrontRange())
|
attributedString.addAttributes(attributes, range: frontRange)
|
||||||
attributedString.addAttributes(_attributes, range: getBackRange())
|
attributedString.addAttributes(attributes, range: backRange)
|
||||||
}
|
}
|
||||||
attributedText = attributedString
|
self.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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc public func setActionTextString(_ actionText: String?) {
|
@objc public func setActionTextString(_ actionText: String?) {
|
||||||
|
|
||||||
|
createLabel()
|
||||||
self.actionText = actionText
|
self.actionText = actionText
|
||||||
text = getTextFromStringComponents()
|
text = getTextFromStringComponents()
|
||||||
setup()
|
setLabelAttributes()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Used to just reset the texts and actions if already initialized
|
/// Used to just reset the texts and actions if already initialized
|
||||||
@objc public func reset(withActionMap actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) {
|
@objc public func reset(withActionMap actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) {
|
||||||
|
|
||||||
|
createLabel()
|
||||||
frontText = actionMap?.optionalStringForKey(KeyTitlePrefix)
|
frontText = actionMap?.optionalStringForKey(KeyTitlePrefix)
|
||||||
actionText = actionMap?.optionalStringForKey(KeyTitle)
|
actionText = actionMap?.optionalStringForKey(KeyTitle)
|
||||||
backText = actionMap?.optionalStringForKey(KeyTitlePostfix)
|
backText = actionMap?.optionalStringForKey(KeyTitlePostfix)
|
||||||
|
|
||||||
actionBlock = {
|
|
||||||
MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegateObject: delegateObject)
|
|
||||||
}
|
|
||||||
|
|
||||||
text = getTextFromStringComponents()
|
text = getTextFromStringComponents()
|
||||||
setup()
|
actionBlock = label?.createActionBlockFrom(actionMap: actionMap, additionalData: additionalData, delegateObject: delegateObject)
|
||||||
|
setLabelAttributes()
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------
|
//------------------------------------------------------
|
||||||
@ -539,20 +408,18 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt
|
|||||||
|
|
||||||
@available(*, deprecated)
|
@available(*, deprecated)
|
||||||
public init(frontText: String?, actionText: String?, backText: String?, actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, actionDelegate delegate: ActionObjectDelegate?, buttonDelegate: ButtonObjectDelegate?) {
|
public init(frontText: String?, actionText: String?, backText: String?, actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, actionDelegate delegate: ActionObjectDelegate?, buttonDelegate: ButtonObjectDelegate?) {
|
||||||
super.init(frame: CGRect.zero)
|
super.init(frame: .zero)
|
||||||
|
|
||||||
setFrontText(frontText, actionText: actionText, actionMap: actionMap, backText: backText, additionalData: additionalData, delegate: delegate, buttonDelegate: buttonDelegate)
|
setFrontText(frontText, actionText: actionText, actionMap: actionMap, backText: backText, additionalData: additionalData, delegate: delegate, buttonDelegate: buttonDelegate)
|
||||||
}
|
}
|
||||||
|
|
||||||
@available(*, deprecated)
|
@available(*, deprecated)
|
||||||
public convenience init(actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, actionDelegate delegate: ActionObjectDelegate?, buttonDelegate: ButtonObjectDelegate?) {
|
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)
|
self.init(frontText: actionMap?.optionalStringForKey(KeyTitlePrefix), actionText: actionMap?.optionalStringForKey(KeyTitle), backText: actionMap?.optionalStringForKey(KeyTitlePostfix), actionMap: actionMap, additionalData: additionalData, actionDelegate: delegate, buttonDelegate: buttonDelegate)
|
||||||
}
|
}
|
||||||
|
|
||||||
@available(*, deprecated)
|
@available(*, deprecated)
|
||||||
public convenience init(frontText: String?, backText: String?, actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, actionDelegate delegate: ActionObjectDelegate?, buttonDelegate: ButtonObjectDelegate?) {
|
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)
|
self.init(frontText: frontText, actionText: actionMap?.optionalStringForKey(KeyTitle), backText: backText, actionMap: actionMap, additionalData: additionalData, actionDelegate: delegate, buttonDelegate: buttonDelegate)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -583,29 +450,18 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt
|
|||||||
|
|
||||||
setText(fullText, startTag: startTag, endTag: endTag)
|
setText(fullText, startTag: startTag, endTag: endTag)
|
||||||
|
|
||||||
weak var weakDelegate: ActionObjectDelegate? = delegate
|
actionBlock = { [weak delegate] in
|
||||||
|
MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegate: delegate as? CoreObjectActionLoadPresentDelegate)
|
||||||
actionBlock = {
|
|
||||||
MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegate: weakDelegate as? CoreObjectActionLoadPresentDelegate)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@available(*, deprecated)
|
@available(*, deprecated)
|
||||||
private func setActionMap(_ actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, actionDelegate delegate: ActionObjectDelegate?, buttonDelegate: ButtonObjectDelegate?) {
|
private func setActionMap(_ actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, actionDelegate delegate: ActionObjectDelegate?, buttonDelegate: ButtonObjectDelegate?) {
|
||||||
|
|
||||||
weak var weakSelf: LabelWithInternalButton? = self
|
actionBlock = { [weak self, weak delegate, weak buttonDelegate] in
|
||||||
weak var weakDelegate: ActionObjectDelegate? = delegate
|
|
||||||
weak var weakButtonDelegate: ButtonObjectDelegate? = buttonDelegate
|
|
||||||
|
|
||||||
actionBlock = {
|
if let wSelf = self, buttonDelegate?.button?(wSelf, shouldPerformActionWithMap: actionMap, additionalData: additionalData) ?? true {
|
||||||
var performAction = true
|
MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegate: delegate as? CoreObjectActionLoadPresentDelegate)
|
||||||
|
|
||||||
if let wSelf = weakSelf, let wButtonDelegate = weakButtonDelegate, wButtonDelegate.responds(to: #selector(ButtonObjectDelegate.button(_:shouldPerformActionWithMap:additionalData:))) {
|
|
||||||
performAction = wButtonDelegate.button?(wSelf, shouldPerformActionWithMap: actionMap, additionalData: additionalData) ?? false
|
|
||||||
}
|
|
||||||
|
|
||||||
if performAction {
|
|
||||||
MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegate: weakDelegate as? CoreObjectActionLoadPresentDelegate)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -618,12 +474,13 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt
|
|||||||
@available(*, deprecated)
|
@available(*, deprecated)
|
||||||
@objc public func setFrontText(_ frontText: String?, actionText: String?, actionMap: [AnyHashable: Any]?, backText: String?, additionalData: [AnyHashable: Any]?, delegate: ActionObjectDelegate?, buttonDelegate: ButtonObjectDelegate?) {
|
@objc public func setFrontText(_ frontText: String?, actionText: String?, actionMap: [AnyHashable: Any]?, backText: String?, additionalData: [AnyHashable: Any]?, delegate: ActionObjectDelegate?, buttonDelegate: ButtonObjectDelegate?) {
|
||||||
|
|
||||||
|
createLabel()
|
||||||
self.frontText = frontText
|
self.frontText = frontText
|
||||||
setActionMap(actionMap, additionalData: additionalData, actionDelegate: delegate, buttonDelegate: buttonDelegate)
|
|
||||||
self.actionText = actionText
|
self.actionText = actionText
|
||||||
self.backText = backText
|
self.backText = backText
|
||||||
text = getTextFromStringComponents()
|
text = getTextFromStringComponents()
|
||||||
setup()
|
setActionMap(actionMap, additionalData: additionalData, actionDelegate: delegate, buttonDelegate: buttonDelegate)
|
||||||
|
setLabelAttributes()
|
||||||
}
|
}
|
||||||
|
|
||||||
@available(*, deprecated)
|
@available(*, deprecated)
|
||||||
@ -644,10 +501,8 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let b2Font = MFStyler.fontB2(),
|
if let b2Font = MFStyler.fontB2(),
|
||||||
let actions = actionMap,
|
let actions = actionMap, actions.keys.count > 0,
|
||||||
actions.keys.count > 0,
|
let actionString = actions.optionalStringForKey(KeyTitle), !actionString.isEmpty {
|
||||||
let actionString = actions.optionalStringForKey(KeyTitle),
|
|
||||||
!actionString.isEmpty {
|
|
||||||
|
|
||||||
let actionStringOnLine = actionString + (addNewLine ? "\n" : " ")
|
let actionStringOnLine = actionString + (addNewLine ? "\n" : " ")
|
||||||
actionText = actionStringOnLine
|
actionText = actionStringOnLine
|
||||||
@ -664,7 +519,6 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt
|
|||||||
}
|
}
|
||||||
|
|
||||||
attributedText = mutableAttributedString
|
attributedText = mutableAttributedString
|
||||||
// Added this line for underlining
|
|
||||||
setAlternateActionTextAttributes([NSAttributedString.Key.underlineStyle: NSNumber(value: NSUnderlineStyle.single.rawValue)])
|
setAlternateActionTextAttributes([NSAttributedString.Key.underlineStyle: NSNumber(value: NSUnderlineStyle.single.rawValue)])
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -712,23 +566,22 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt
|
|||||||
@available(*, deprecated)
|
@available(*, deprecated)
|
||||||
@objc public func reset(withActionMap actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, delegate: ActionObjectDelegate?) {
|
@objc public func reset(withActionMap actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, delegate: ActionObjectDelegate?) {
|
||||||
|
|
||||||
|
createLabel()
|
||||||
frontText = actionMap?.optionalStringForKey(KeyTitlePrefix)
|
frontText = actionMap?.optionalStringForKey(KeyTitlePrefix)
|
||||||
actionText = actionMap?.optionalStringForKey(KeyTitle)
|
actionText = actionMap?.optionalStringForKey(KeyTitle)
|
||||||
backText = actionMap?.optionalStringForKey(KeyTitlePostfix)
|
backText = actionMap?.optionalStringForKey(KeyTitlePostfix)
|
||||||
|
|
||||||
weak var weakDelegate: ActionObjectDelegate? = delegate
|
|
||||||
|
|
||||||
actionBlock = {
|
|
||||||
MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegate: weakDelegate as? CoreObjectActionLoadPresentDelegate)
|
|
||||||
}
|
|
||||||
|
|
||||||
text = getTextFromStringComponents()
|
text = getTextFromStringComponents()
|
||||||
setup()
|
|
||||||
|
actionBlock = { [weak delegate] in
|
||||||
|
MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegate: delegate as? CoreObjectActionLoadPresentDelegate)
|
||||||
|
}
|
||||||
|
setLabelAttributes()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Atomization
|
//------------------------------------------------------
|
||||||
extension LabelWithInternalButton: MVMCoreUIMoleculeViewProtocol {
|
// MARK: - Atomization
|
||||||
|
//------------------------------------------------------
|
||||||
|
|
||||||
// Default values for view.
|
// Default values for view.
|
||||||
@objc open func setAsMolecule() {
|
@objc open func setAsMolecule() {
|
||||||
|
|
||||||
|
|||||||
183
MVMCoreUI/Atoms/Views/LeftRightLabelView.swift
Normal file
183
MVMCoreUI/Atoms/Views/LeftRightLabelView.swift
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
//
|
||||||
|
// LeftRightLabelView.swift
|
||||||
|
// MVMCoreUI
|
||||||
|
//
|
||||||
|
// Created by Christiano, Kevin on 5/20/19.
|
||||||
|
// Copyright © 2019 Verizon Wireless. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
|
||||||
|
@objcMembers open class LeftRightLabelView: ViewConstrainingView {
|
||||||
|
//------------------------------------------------------
|
||||||
|
// MARK: - Outlets
|
||||||
|
//------------------------------------------------------
|
||||||
|
|
||||||
|
let leftTextLabel = Label.commonLabelB1(true)
|
||||||
|
let rightTextLabel = Label.commonLabelB1(true)
|
||||||
|
|
||||||
|
//------------------------------------------------------
|
||||||
|
// MARK: - Constraints
|
||||||
|
//------------------------------------------------------
|
||||||
|
|
||||||
|
var rightTextLabelLeading: NSLayoutConstraint?
|
||||||
|
var leftTextLabelTrailing: NSLayoutConstraint?
|
||||||
|
|
||||||
|
//------------------------------------------------------
|
||||||
|
// MARK: - Initialization
|
||||||
|
//------------------------------------------------------
|
||||||
|
|
||||||
|
public init() {
|
||||||
|
super.init(frame: .zero)
|
||||||
|
}
|
||||||
|
|
||||||
|
public override init(frame: CGRect) {
|
||||||
|
super.init(frame: frame)
|
||||||
|
}
|
||||||
|
|
||||||
|
required public init?(coder aDecoder: NSCoder) {
|
||||||
|
super.init(coder: aDecoder)
|
||||||
|
}
|
||||||
|
|
||||||
|
public convenience init(json: [AnyHashable: Any]?, delegateObject: DelegateObject?, additionalData: [AnyHashable: Any]?) {
|
||||||
|
self.init()
|
||||||
|
setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
|
||||||
|
}
|
||||||
|
|
||||||
|
override open func setupView() {
|
||||||
|
super.setupView()
|
||||||
|
|
||||||
|
guard subviews.isEmpty else { return }
|
||||||
|
|
||||||
|
addSubview(leftTextLabel)
|
||||||
|
addSubview(rightTextLabel)
|
||||||
|
|
||||||
|
leftTextLabel.textAlignment = .left
|
||||||
|
rightTextLabel.textAlignment = .right
|
||||||
|
|
||||||
|
constrainBothLabels()
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------
|
||||||
|
// MARK: - View Lifecycle
|
||||||
|
//------------------------------------------------------
|
||||||
|
|
||||||
|
override open func updateView(_ size: CGFloat) {
|
||||||
|
super.updateView(size)
|
||||||
|
|
||||||
|
leftTextLabel.updateView(size)
|
||||||
|
rightTextLabel.updateView(size)
|
||||||
|
|
||||||
|
// Resolves text layout issues found between both dynamically sized labels, number is not exact but performs as required.
|
||||||
|
if leftTextLabel.hasText && rightTextLabel.hasText {
|
||||||
|
let padding = MFStyler.defaultHorizontalPadding(forSize: size) * 2
|
||||||
|
let maximumTextWidth = (size - (padding + 16)) * 0.4
|
||||||
|
// Subtracting 10 resolves issues of SE and iPad
|
||||||
|
rightTextLabel.preferredMaxLayoutWidth = round(maximumTextWidth) - 10
|
||||||
|
} else {
|
||||||
|
rightTextLabel.preferredMaxLayoutWidth = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------
|
||||||
|
// MARK: - Setup
|
||||||
|
//------------------------------------------------------
|
||||||
|
|
||||||
|
private func constrainBothLabels() {
|
||||||
|
|
||||||
|
leftTextLabel.topAnchor.constraint(equalTo: topAnchor).isActive = true
|
||||||
|
leftTextLabel.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor).isActive = true
|
||||||
|
|
||||||
|
let leftTextBottom = leftTextLabel.bottomAnchor.constraint(equalTo: bottomAnchor)
|
||||||
|
leftTextBottom.priority = UILayoutPriority(249)
|
||||||
|
leftTextBottom.isActive = true
|
||||||
|
|
||||||
|
bottomAnchor.constraint(greaterThanOrEqualTo: leftTextLabel.bottomAnchor).isActive = true
|
||||||
|
|
||||||
|
rightTextLabelLeading = rightTextLabel.leadingAnchor.constraint(equalTo: leftTextLabel.trailingAnchor, constant: 16)
|
||||||
|
rightTextLabelLeading?.isActive = true
|
||||||
|
|
||||||
|
rightTextLabel.topAnchor.constraint(equalTo: topAnchor).isActive = true
|
||||||
|
let rightLayout = layoutMarginsGuide.trailingAnchor.constraint(equalTo: rightTextLabel.trailingAnchor)
|
||||||
|
rightLayout.priority = UILayoutPriority(rawValue: 995)
|
||||||
|
rightLayout.isActive = true
|
||||||
|
|
||||||
|
let rightTextBottom = rightTextLabel.bottomAnchor.constraint(equalTo: bottomAnchor)
|
||||||
|
rightTextBottom.priority = UILayoutPriority(rawValue: 249)
|
||||||
|
rightTextBottom.isActive = true
|
||||||
|
|
||||||
|
bottomAnchor.constraint(greaterThanOrEqualTo: rightTextLabel.bottomAnchor).isActive = true
|
||||||
|
|
||||||
|
let leftTextWidth = leftTextLabel.widthAnchor.constraint(greaterThanOrEqualTo: layoutMarginsGuide.widthAnchor, multiplier: 0.6)
|
||||||
|
leftTextWidth.priority = UILayoutPriority(rawValue: 995)
|
||||||
|
leftTextWidth.isActive = true
|
||||||
|
|
||||||
|
let rightTextWidth = rightTextLabel.widthAnchor.constraint(lessThanOrEqualTo: layoutMarginsGuide.widthAnchor, multiplier: 0.4)
|
||||||
|
rightTextWidth.priority = UILayoutPriority(rawValue: 906)
|
||||||
|
rightTextWidth.isActive = true
|
||||||
|
|
||||||
|
leftTextLabel.setContentHuggingPriority(UILayoutPriority(rawValue: 901), for: .horizontal)
|
||||||
|
rightTextLabel.setContentHuggingPriority(UILayoutPriority(rawValue: 902), for: .horizontal)
|
||||||
|
|
||||||
|
leftTextLabel.setContentHuggingPriority(.required, for: .vertical)
|
||||||
|
rightTextLabel.setContentHuggingPriority(.required, for: .vertical)
|
||||||
|
|
||||||
|
leftTextLabel.setContentCompressionResistancePriority(.required, for: .vertical)
|
||||||
|
rightTextLabel.setContentCompressionResistancePriority(.required, for: .vertical)
|
||||||
|
rightTextLabel.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 902), for: .horizontal)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func constrainLeftLabel() {
|
||||||
|
|
||||||
|
deactivateMiddleConstraint()
|
||||||
|
leftTextLabelTrailing = layoutMarginsGuide.trailingAnchor.constraint(equalTo: leftTextLabel.trailingAnchor)
|
||||||
|
leftTextLabelTrailing?.isActive = true
|
||||||
|
}
|
||||||
|
|
||||||
|
private func constrainRightLabel() {
|
||||||
|
|
||||||
|
deactivateMiddleConstraint()
|
||||||
|
rightTextLabelLeading = rightTextLabel.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor)
|
||||||
|
rightTextLabelLeading?.isActive = true
|
||||||
|
}
|
||||||
|
|
||||||
|
override open func reset() {
|
||||||
|
super.reset()
|
||||||
|
|
||||||
|
deactivateMiddleConstraint()
|
||||||
|
constrainBothLabels()
|
||||||
|
leftTextLabel.text = ""
|
||||||
|
rightTextLabel.text = ""
|
||||||
|
backgroundColor = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
private func deactivateMiddleConstraint() {
|
||||||
|
|
||||||
|
leftTextLabelTrailing?.isActive = false
|
||||||
|
rightTextLabelLeading?.isActive = false
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------
|
||||||
|
// MARK: - Atomization
|
||||||
|
//------------------------------------------------------
|
||||||
|
|
||||||
|
open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: DelegateObject?, additionalData: [AnyHashable: Any]?) {
|
||||||
|
super.setWithJSON(json, delegateObject: delegateObject as? MVMCoreUIDelegateObject, additionalData: additionalData)
|
||||||
|
|
||||||
|
guard let dictionary = json else { return }
|
||||||
|
|
||||||
|
leftTextLabel.setWithJSON(dictionary.optionalDictionaryForKey("leftText"), delegateObject: delegateObject as? MVMCoreUIDelegateObject, additionalData: additionalData)
|
||||||
|
rightTextLabel.setWithJSON(dictionary.optionalDictionaryForKey("rightText"), delegateObject: delegateObject as? MVMCoreUIDelegateObject, additionalData: additionalData)
|
||||||
|
|
||||||
|
if let backgroundColorHex = dictionary[KeyBackgroundColor] as? String {
|
||||||
|
backgroundColor = UIColor.mfGet(forHex: backgroundColorHex)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !leftTextLabel.hasText {
|
||||||
|
constrainRightLabel()
|
||||||
|
} else if !rightTextLabel.hasText {
|
||||||
|
constrainLeftLabel()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -15,9 +15,4 @@
|
|||||||
|
|
||||||
+ (nullable instancetype)createWithDelegate:(nullable id <UITextFieldDelegate, MFTextFieldDelegate>)delegate;
|
+ (nullable instancetype)createWithDelegate:(nullable id <UITextFieldDelegate, MFTextFieldDelegate>)delegate;
|
||||||
|
|
||||||
// Change the alignment of the label
|
|
||||||
- (void)alignLeft;
|
|
||||||
- (void)alignCenter;
|
|
||||||
- (void)alignRight;
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@ -10,9 +10,6 @@
|
|||||||
#import "NSLayoutConstraint+MFConvenience.h"
|
#import "NSLayoutConstraint+MFConvenience.h"
|
||||||
|
|
||||||
@interface MVMCoreUITextFieldView ()
|
@interface MVMCoreUITextFieldView ()
|
||||||
@property (weak, nonatomic) NSLayoutConstraint *alignCenterPin;
|
|
||||||
@property (weak, nonatomic) NSLayoutConstraint *alignCenterLeftPin;
|
|
||||||
@property (weak, nonatomic) NSLayoutConstraint *alignCenterRightPin;
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation MVMCoreUITextFieldView
|
@implementation MVMCoreUITextFieldView
|
||||||
@ -31,74 +28,11 @@
|
|||||||
mfTextField.translatesAutoresizingMaskIntoConstraints = NO;
|
mfTextField.translatesAutoresizingMaskIntoConstraints = NO;
|
||||||
[self addSubview:mfTextField];
|
[self addSubview:mfTextField];
|
||||||
self.mvmTextField = mfTextField;
|
self.mvmTextField = mfTextField;
|
||||||
|
[self pinViewToSuperView:mfTextField];
|
||||||
NSLayoutConstraint *leftPin = [NSLayoutConstraint constraintWithItem:mfTextField attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeft multiplier:1.0 constant:0];
|
|
||||||
self.leftPin = leftPin;
|
|
||||||
leftPin.active = YES;
|
|
||||||
|
|
||||||
NSLayoutConstraint *topPin = [NSLayoutConstraint constraintWithItem:mfTextField attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTop multiplier:1.0 constant:0];
|
|
||||||
self.topPin = topPin;
|
|
||||||
topPin.active = YES;
|
|
||||||
|
|
||||||
NSLayoutConstraint *bottomPin = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:mfTextField attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0];
|
|
||||||
self.bottomPin = bottomPin;
|
|
||||||
bottomPin.active = YES;
|
|
||||||
|
|
||||||
NSLayoutConstraint *rightPin = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:mfTextField attribute:NSLayoutAttributeRight multiplier:1.0 constant:0];
|
|
||||||
self.rightPin = rightPin;
|
|
||||||
rightPin.active = YES;
|
|
||||||
|
|
||||||
// Center alignments
|
|
||||||
NSLayoutConstraint *alignCenter = [NSLayoutConstraint constraintWithItem:mfTextField attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0];
|
|
||||||
self.alignCenterPin = alignCenter;
|
|
||||||
alignCenter.active = YES;
|
|
||||||
|
|
||||||
NSLayoutConstraint *centerLeftPin = [NSLayoutConstraint constraintWithItem:mfTextField attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:self attribute:NSLayoutAttributeLeft multiplier:1.0 constant:0];
|
|
||||||
self.alignCenterLeftPin = centerLeftPin;
|
|
||||||
centerLeftPin.active = YES;
|
|
||||||
|
|
||||||
NSLayoutConstraint *centerRightPin = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:mfTextField attribute:NSLayoutAttributeRight multiplier:1.0 constant:0];
|
|
||||||
self.alignCenterRightPin = centerRightPin;
|
|
||||||
centerRightPin.active = YES;
|
|
||||||
|
|
||||||
[self alignLeft];
|
[self alignLeft];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)alignLeft {
|
|
||||||
self.alignCenterPin.active = NO;
|
|
||||||
self.alignCenterLeftPin.active = NO;
|
|
||||||
self.alignCenterRightPin.active = NO;
|
|
||||||
self.leftPin.active = YES;
|
|
||||||
self.rightPin.active = YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)alignCenter {
|
|
||||||
self.alignCenterPin.active = YES;
|
|
||||||
self.alignCenterLeftPin.active = YES;
|
|
||||||
self.alignCenterRightPin.active = YES;
|
|
||||||
self.leftPin.active = NO;
|
|
||||||
self.rightPin.active = NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)alignRight {
|
|
||||||
self.alignCenterPin.active = NO;
|
|
||||||
self.alignCenterLeftPin.active = NO;
|
|
||||||
self.alignCenterRightPin.active = NO;
|
|
||||||
self.leftPin.active = YES;
|
|
||||||
self.rightPin.active = YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setLeftPinConstant:(CGFloat)constant {
|
|
||||||
self.leftPin.constant = constant;
|
|
||||||
self.alignCenterLeftPin.constant = constant;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setRightPinConstant:(CGFloat)constant {
|
|
||||||
self.rightPin.constant = constant;
|
|
||||||
self.alignCenterRightPin.constant = constant;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)resetConstraints {
|
- (void)resetConstraints {
|
||||||
[super resetConstraints];
|
[super resetConstraints];
|
||||||
[self alignLeft];
|
[self alignLeft];
|
||||||
|
|||||||
@ -20,11 +20,6 @@
|
|||||||
// inits with two buttons.
|
// inits with two buttons.
|
||||||
- (nullable instancetype)initWithTwoButtons;
|
- (nullable instancetype)initWithTwoButtons;
|
||||||
|
|
||||||
// Change the alignment of the button. Default is left.
|
|
||||||
- (void)alignLeft;
|
|
||||||
- (void)alignCenter;
|
|
||||||
- (void)alignRight;
|
|
||||||
|
|
||||||
// To add dotted underline below text button, in case of one button
|
// To add dotted underline below text button, in case of one button
|
||||||
- (void)addDotLineBelowButton;
|
- (void)addDotLineBelowButton;
|
||||||
|
|
||||||
|
|||||||
@ -14,10 +14,6 @@
|
|||||||
#import <MVMCoreUI/UIColor+MFConvenience.h>
|
#import <MVMCoreUI/UIColor+MFConvenience.h>
|
||||||
|
|
||||||
@interface TextButtonView ()
|
@interface TextButtonView ()
|
||||||
|
|
||||||
@property (weak, nonatomic) NSLayoutConstraint *alignCenterPin;
|
|
||||||
@property (weak, nonatomic) NSLayoutConstraint *alignCenterLeftPin;
|
|
||||||
@property (weak, nonatomic) NSLayoutConstraint *alignCenterRightPin;
|
|
||||||
@property (strong, nonatomic) UIView *dotLine;
|
@property (strong, nonatomic) UIView *dotLine;
|
||||||
|
|
||||||
// Sets up the view.
|
// Sets up the view.
|
||||||
@ -78,37 +74,7 @@
|
|||||||
button.translatesAutoresizingMaskIntoConstraints = NO;
|
button.translatesAutoresizingMaskIntoConstraints = NO;
|
||||||
[self addSubview:button];
|
[self addSubview:button];
|
||||||
self.textButton = button;
|
self.textButton = button;
|
||||||
|
[self pinViewToSuperView:button];
|
||||||
// Align left and right constants.
|
|
||||||
NSLayoutConstraint *leftPin = [NSLayoutConstraint constraintWithItem:button attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeft multiplier:1.0 constant:0];
|
|
||||||
self.leftPin = leftPin;
|
|
||||||
leftPin.active = YES;
|
|
||||||
|
|
||||||
NSLayoutConstraint *topPin = [NSLayoutConstraint constraintWithItem:button attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTop multiplier:1.0 constant:0];
|
|
||||||
self.topPin = topPin;
|
|
||||||
topPin.active = YES;
|
|
||||||
|
|
||||||
NSLayoutConstraint *bottomPin = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:button attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0];
|
|
||||||
self.bottomPin = bottomPin;
|
|
||||||
bottomPin.active = YES;
|
|
||||||
|
|
||||||
NSLayoutConstraint *rightPin = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:button attribute:NSLayoutAttributeRight multiplier:1.0 constant:0];
|
|
||||||
self.rightPin = rightPin;
|
|
||||||
rightPin.active = YES;
|
|
||||||
|
|
||||||
// Center alignments
|
|
||||||
NSLayoutConstraint *alignCenter = [NSLayoutConstraint constraintWithItem:button attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0];
|
|
||||||
self.alignCenterPin = alignCenter;
|
|
||||||
alignCenter.active = YES;
|
|
||||||
|
|
||||||
NSLayoutConstraint *centerLeftPin = [NSLayoutConstraint constraintWithItem:button attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:self attribute:NSLayoutAttributeLeft multiplier:1.0 constant:0];
|
|
||||||
self.alignCenterLeftPin = centerLeftPin;
|
|
||||||
centerLeftPin.active = YES;
|
|
||||||
|
|
||||||
NSLayoutConstraint *centerRightPin = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:button attribute:NSLayoutAttributeRight multiplier:1.0 constant:0];
|
|
||||||
self.alignCenterRightPin = centerRightPin;
|
|
||||||
centerRightPin.active = YES;
|
|
||||||
|
|
||||||
[self alignLeft];
|
[self alignLeft];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -154,40 +120,6 @@
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)alignLeft {
|
|
||||||
self.alignCenterPin.active = NO;
|
|
||||||
self.alignCenterLeftPin.active = NO;
|
|
||||||
self.alignCenterRightPin.active = YES;
|
|
||||||
self.leftPin.active = YES;
|
|
||||||
self.rightPin.active = NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)alignCenter {
|
|
||||||
self.alignCenterPin.active = YES;
|
|
||||||
self.alignCenterLeftPin.active = YES;
|
|
||||||
self.alignCenterRightPin.active = YES;
|
|
||||||
self.leftPin.active = NO;
|
|
||||||
self.rightPin.active = NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)alignRight {
|
|
||||||
self.alignCenterPin.active = NO;
|
|
||||||
self.alignCenterLeftPin.active = YES;
|
|
||||||
self.alignCenterRightPin.active = NO;
|
|
||||||
self.leftPin.active = NO;
|
|
||||||
self.rightPin.active = YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setLeftPinConstant:(CGFloat)constant {
|
|
||||||
[super setLeftPinConstant:constant];
|
|
||||||
self.alignCenterLeftPin.constant = constant;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setRightPinConstant:(CGFloat)constant {
|
|
||||||
[super setRightPinConstant:constant];
|
|
||||||
self.alignCenterRightPin.constant = constant;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)resetConstraints {
|
- (void)resetConstraints {
|
||||||
[super resetConstraints];
|
[super resetConstraints];
|
||||||
[self alignLeft];
|
[self alignLeft];
|
||||||
|
|||||||
@ -17,9 +17,24 @@
|
|||||||
@property (nullable, strong, nonatomic) NSLayoutConstraint *topPin;
|
@property (nullable, strong, nonatomic) NSLayoutConstraint *topPin;
|
||||||
@property (nullable, strong, nonatomic) NSLayoutConstraint *bottomPin;
|
@property (nullable, strong, nonatomic) NSLayoutConstraint *bottomPin;
|
||||||
|
|
||||||
|
@property (nullable, strong, nonatomic) NSLayoutConstraint *alignCenterPin;
|
||||||
|
@property (nullable, strong, nonatomic) NSLayoutConstraint *alignCenterLeftPin;
|
||||||
|
@property (nullable, strong, nonatomic) NSLayoutConstraint *alignCenterRightPin;
|
||||||
|
|
||||||
|
@property (nullable, strong, nonatomic) NSLayoutConstraint *alignCenterVerticalPin;
|
||||||
|
@property (nullable, strong, nonatomic) NSLayoutConstraint *alignCenterTopPin;
|
||||||
|
@property (nullable, strong, nonatomic) NSLayoutConstraint *alignCenterBottomPin;
|
||||||
|
|
||||||
|
@property (nullable, strong, nonatomic) NSLayoutConstraint *leftPinLow;
|
||||||
|
@property (nullable, strong, nonatomic) NSLayoutConstraint *rightPinLow;
|
||||||
|
@property (nullable, strong, nonatomic) NSLayoutConstraint *topPinLow;
|
||||||
|
@property (nullable, strong, nonatomic) NSLayoutConstraint *bottomPinLow;
|
||||||
|
|
||||||
|
|
||||||
// In updateView, will set horizontal padding to default if set to YES.
|
// In updateView, will set horizontal padding to default if set to YES.
|
||||||
@property (nonatomic) BOOL updateViewHorizontalDefaults;
|
@property (nonatomic) BOOL updateViewHorizontalDefaults;
|
||||||
|
|
||||||
|
|
||||||
// Returns an empty view
|
// Returns an empty view
|
||||||
+ (nonnull ViewConstrainingView *)emptyView;
|
+ (nonnull ViewConstrainingView *)emptyView;
|
||||||
|
|
||||||
@ -43,6 +58,7 @@
|
|||||||
|
|
||||||
// Pins all edges to its super. 0 constant
|
// Pins all edges to its super. 0 constant
|
||||||
- (void)pinToSuperView;
|
- (void)pinToSuperView;
|
||||||
|
- (void)pinViewToSuperView:(nonnull UIView *)view;
|
||||||
|
|
||||||
// Resets all the constraints to default.
|
// Resets all the constraints to default.
|
||||||
- (void)resetConstraints;
|
- (void)resetConstraints;
|
||||||
@ -53,4 +69,17 @@
|
|||||||
// Add a view to be constrained in this view.
|
// Add a view to be constrained in this view.
|
||||||
- (void)addConstrainedView:(nonnull UIView *)view;
|
- (void)addConstrainedView:(nonnull UIView *)view;
|
||||||
|
|
||||||
|
// Change the alignment of the label
|
||||||
|
- (void)alignLeft;
|
||||||
|
- (void)alignCenterHorizontal;
|
||||||
|
- (void)alignRight;
|
||||||
|
- (void)alignFillHorizontal;
|
||||||
|
- (void)alignTop;
|
||||||
|
- (void)alignCenterVertical;
|
||||||
|
- (void)alignBottom;
|
||||||
|
- (void)alignFillVertical;
|
||||||
|
|
||||||
|
/// Convenience function for getting the alignment from a map.
|
||||||
|
+ (UIStackViewAlignment)getAlignmentForString:(nullable NSString *)alignmentString defaultAlignment:(UIStackViewAlignment)defaultAlignment;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@ -45,12 +45,42 @@
|
|||||||
return constrainingView;
|
return constrainingView;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)pinToSuperView {
|
#pragma mark - Constraining
|
||||||
NSDictionary *dictionary = [NSLayoutConstraint constraintPinSubviewToSuperview:self];
|
|
||||||
|
- (void)pinViewToSuperView:(nonnull UIView *)view {
|
||||||
|
NSDictionary *dictionary = [NSLayoutConstraint constraintPinSubviewToSuperview:view];
|
||||||
self.leftPin = dictionary[ConstraintLeading];
|
self.leftPin = dictionary[ConstraintLeading];
|
||||||
self.topPin = dictionary[ConstraintTop];
|
self.topPin = dictionary[ConstraintTop];
|
||||||
self.bottomPin = dictionary[ConstraintBot];
|
self.bottomPin = dictionary[ConstraintBot];
|
||||||
self.rightPin = dictionary[ConstraintTrailing];
|
self.rightPin = dictionary[ConstraintTrailing];
|
||||||
|
|
||||||
|
self.alignCenterPin = [view.centerXAnchor constraintEqualToAnchor:view.superview.centerXAnchor];
|
||||||
|
self.alignCenterLeftPin = [view.leftAnchor constraintGreaterThanOrEqualToAnchor:view.superview.leftAnchor];
|
||||||
|
self.alignCenterRightPin = [view.superview.rightAnchor constraintGreaterThanOrEqualToAnchor:view.rightAnchor];
|
||||||
|
|
||||||
|
self.alignCenterVerticalPin = [view.centerYAnchor constraintEqualToAnchor:view.superview.centerYAnchor];
|
||||||
|
self.alignCenterTopPin = [view.topAnchor constraintGreaterThanOrEqualToAnchor:view.superview.topAnchor];
|
||||||
|
self.alignCenterBottomPin = [view.superview.bottomAnchor constraintGreaterThanOrEqualToAnchor:view.bottomAnchor];
|
||||||
|
|
||||||
|
self.leftPinLow = [view.leftAnchor constraintEqualToAnchor:view.superview.leftAnchor];
|
||||||
|
self.leftPinLow.priority = 200;
|
||||||
|
self.leftPinLow.active = YES;
|
||||||
|
|
||||||
|
self.topPinLow = [view.topAnchor constraintEqualToAnchor:view.superview.topAnchor];
|
||||||
|
self.topPinLow.priority = 200;
|
||||||
|
self.topPinLow.active = YES;
|
||||||
|
|
||||||
|
self.rightPinLow = [view.superview.rightAnchor constraintEqualToAnchor:view.superview.rightAnchor];
|
||||||
|
self.rightPinLow.priority = 200;
|
||||||
|
self.rightPinLow.active = YES;
|
||||||
|
|
||||||
|
self.bottomPinLow = [view.superview.bottomAnchor constraintEqualToAnchor:view.superview.bottomAnchor];
|
||||||
|
self.bottomPinLow.priority = 200;
|
||||||
|
self.bottomPinLow.active = YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)pinToSuperView {
|
||||||
|
[self pinViewToSuperView:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setPinConstantsWithInsets:(UIEdgeInsets)insets {
|
- (void)setPinConstantsWithInsets:(UIEdgeInsets)insets {
|
||||||
@ -66,18 +96,26 @@
|
|||||||
|
|
||||||
- (void)setLeftPinConstant:(CGFloat)constant {
|
- (void)setLeftPinConstant:(CGFloat)constant {
|
||||||
self.leftPin.constant = constant;
|
self.leftPin.constant = constant;
|
||||||
|
self.alignCenterLeftPin.constant = constant;
|
||||||
|
self.leftPinLow.constant = constant;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setRightPinConstant:(CGFloat)constant {
|
- (void)setRightPinConstant:(CGFloat)constant {
|
||||||
self.rightPin.constant = constant;
|
self.rightPin.constant = constant;
|
||||||
|
self.alignCenterRightPin.constant = constant;
|
||||||
|
self.rightPinLow.constant = constant;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setTopPinConstant:(CGFloat)constant {
|
- (void)setTopPinConstant:(CGFloat)constant {
|
||||||
self.topPin.constant = constant;
|
self.topPin.constant = constant;
|
||||||
|
self.alignCenterTopPin.constant = constant;
|
||||||
|
self.topPinLow.constant = constant;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setBottomPinConstant:(CGFloat)constant {
|
- (void)setBottomPinConstant:(CGFloat)constant {
|
||||||
self.bottomPin.constant = constant;
|
self.bottomPin.constant = constant;
|
||||||
|
self.alignCenterBottomPin.constant = constant;
|
||||||
|
self.bottomPinLow.constant = constant;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)show {
|
- (void)show {
|
||||||
@ -100,34 +138,147 @@
|
|||||||
view.translatesAutoresizingMaskIntoConstraints = NO;
|
view.translatesAutoresizingMaskIntoConstraints = NO;
|
||||||
[self addSubview:view];
|
[self addSubview:view];
|
||||||
self.constrainedView = view;
|
self.constrainedView = view;
|
||||||
|
[self pinViewToSuperView:view];
|
||||||
NSLayoutRelation leftRelation;
|
[self alignHorizontal:alignment];
|
||||||
if (alignment == UIStackViewAlignmentFill || alignment == UIStackViewAlignmentLeading || alignment == UIStackViewAlignmentFirstBaseline) {
|
|
||||||
leftRelation = NSLayoutRelationEqual;
|
|
||||||
} else {
|
|
||||||
leftRelation = NSLayoutRelationGreaterThanOrEqual;
|
|
||||||
}
|
|
||||||
NSLayoutRelation rightRelation;
|
|
||||||
if (alignment == UIStackViewAlignmentFill || alignment == UIStackViewAlignmentTrailing || alignment == UIStackViewAlignmentLastBaseline) {
|
|
||||||
rightRelation = NSLayoutRelationEqual;
|
|
||||||
} else {
|
|
||||||
rightRelation = NSLayoutRelationGreaterThanOrEqual;
|
|
||||||
}
|
|
||||||
NSDictionary *dictionary = [NSLayoutConstraint constraintPinSubview:view topRelation:NSLayoutRelationEqual bottomRelation:NSLayoutRelationEqual leftRelation:leftRelation rightRelation:rightRelation];
|
|
||||||
self.leftPin = dictionary[ConstraintLeading];
|
|
||||||
self.topPin = dictionary[ConstraintTop];
|
|
||||||
self.bottomPin = dictionary[ConstraintBot];
|
|
||||||
self.rightPin = dictionary[ConstraintTrailing];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)addConstrainedView:(nonnull UIView *)view {
|
- (void)addConstrainedView:(nonnull UIView *)view {
|
||||||
[self addConstrainedView:view alignment:UIStackViewAlignmentFill];
|
[self addConstrainedView:view alignment:UIStackViewAlignmentFill];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)alignLeft {
|
||||||
|
self.alignCenterPin.active = NO;
|
||||||
|
self.alignCenterLeftPin.active = NO;
|
||||||
|
self.alignCenterRightPin.active = YES;
|
||||||
|
self.leftPin.active = YES;
|
||||||
|
self.rightPin.active = NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)alignCenterHorizontal {
|
||||||
|
self.alignCenterPin.active = YES;
|
||||||
|
self.alignCenterLeftPin.active = YES;
|
||||||
|
self.alignCenterRightPin.active = YES;
|
||||||
|
self.leftPin.active = NO;
|
||||||
|
self.rightPin.active = NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)alignRight {
|
||||||
|
self.alignCenterPin.active = NO;
|
||||||
|
self.alignCenterLeftPin.active = YES;
|
||||||
|
self.alignCenterRightPin.active = NO;
|
||||||
|
self.leftPin.active = NO;
|
||||||
|
self.rightPin.active = YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)alignFillHorizontal {
|
||||||
|
self.alignCenterPin.active = NO;
|
||||||
|
self.alignCenterLeftPin.active = NO;
|
||||||
|
self.alignCenterRightPin.active = NO;
|
||||||
|
self.leftPin.active = YES;
|
||||||
|
self.rightPin.active = YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)alignTop {
|
||||||
|
self.alignCenterVerticalPin.active = NO;
|
||||||
|
self.alignCenterTopPin.active = NO;
|
||||||
|
self.alignCenterBottomPin.active = YES;
|
||||||
|
self.topPin.active = YES;
|
||||||
|
self.bottomPin.active = NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)alignCenterVertical {
|
||||||
|
self.alignCenterVerticalPin.active = YES;
|
||||||
|
self.alignCenterTopPin.active = YES;
|
||||||
|
self.alignCenterBottomPin.active = YES;
|
||||||
|
self.topPin.active = NO;
|
||||||
|
self.bottomPin.active = NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)alignBottom {
|
||||||
|
self.alignCenterVerticalPin.active = NO;
|
||||||
|
self.alignCenterTopPin.active = YES;
|
||||||
|
self.alignCenterBottomPin.active = NO;
|
||||||
|
self.topPin.active = NO;
|
||||||
|
self.bottomPin.active = YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)alignFillVertical {
|
||||||
|
self.alignCenterVerticalPin.active = NO;
|
||||||
|
self.alignCenterTopPin.active = NO;
|
||||||
|
self.alignCenterBottomPin.active = NO;
|
||||||
|
self.topPin.active = YES;
|
||||||
|
self.bottomPin.active = YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (UIStackViewAlignment)getAlignmentForString:(nullable NSString *)alignmentString defaultAlignment:(UIStackViewAlignment)defaultAlignment {
|
||||||
|
if ([alignmentString isEqualToString:@"leading"]) {
|
||||||
|
return UIStackViewAlignmentLeading;
|
||||||
|
} else if ([alignmentString isEqualToString:@"trailing"]) {
|
||||||
|
return UIStackViewAlignmentTrailing;
|
||||||
|
} else if ([alignmentString isEqualToString:@"center"]) {
|
||||||
|
return UIStackViewAlignmentCenter;
|
||||||
|
} else if ([alignmentString isEqualToString:@"fill"]) {
|
||||||
|
return UIStackViewAlignmentFill;
|
||||||
|
} else {
|
||||||
|
return defaultAlignment;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - MVMCoreUIViewConstrainingProtocol
|
||||||
|
|
||||||
|
- (void)alignHorizontal:(UIStackViewAlignment)alignment {
|
||||||
|
switch (alignment) {
|
||||||
|
case UIStackViewAlignmentCenter:
|
||||||
|
[self alignCenterHorizontal];
|
||||||
|
break;
|
||||||
|
case UIStackViewAlignmentLeading:
|
||||||
|
[self alignLeft];
|
||||||
|
break;
|
||||||
|
case UIStackViewAlignmentTrailing:
|
||||||
|
[self alignRight];
|
||||||
|
break;
|
||||||
|
case UIStackViewAlignmentFill:
|
||||||
|
[self alignFillHorizontal];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)alignVertical:(UIStackViewAlignment)alignment {
|
||||||
|
switch (alignment) {
|
||||||
|
case UIStackViewAlignmentCenter:
|
||||||
|
[self alignCenterVertical];
|
||||||
|
break;
|
||||||
|
case UIStackViewAlignmentLeading:
|
||||||
|
[self alignTop];
|
||||||
|
break;
|
||||||
|
case UIStackViewAlignmentTrailing:
|
||||||
|
[self alignBottom];
|
||||||
|
break;
|
||||||
|
case UIStackViewAlignmentFill:
|
||||||
|
[self alignFillVertical];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)shouldSetHorizontalMargins:(BOOL)shouldSet {
|
||||||
|
self.updateViewHorizontalDefaults = shouldSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - MVMCoreViewProtocol
|
||||||
|
|
||||||
- (void)setupView {
|
- (void)setupView {
|
||||||
[super setupView];
|
[super setupView];
|
||||||
self.translatesAutoresizingMaskIntoConstraints = NO;
|
self.translatesAutoresizingMaskIntoConstraints = NO;
|
||||||
self.backgroundColor = [UIColor clearColor];
|
self.backgroundColor = [UIColor clearColor];
|
||||||
|
if (@available(iOS 11.0, *)) {
|
||||||
|
self.directionalLayoutMargins = NSDirectionalEdgeInsetsZero;
|
||||||
|
} else {
|
||||||
|
self.layoutMargins = UIEdgeInsetsZero;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)updateView:(CGFloat)size {
|
- (void)updateView:(CGFloat)size {
|
||||||
@ -145,14 +296,14 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma mark - MVMCoreUIMoleculeViewProtocol
|
||||||
|
|
||||||
- (void)reset {
|
- (void)reset {
|
||||||
if ([self.constrainedView respondsToSelector:@selector(reset)]) {
|
if ([self.constrainedView respondsToSelector:@selector(reset)]) {
|
||||||
[self.constrainedView performSelector:@selector(reset)];
|
[self.constrainedView performSelector:@selector(reset)];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - MVMCoreUIMoleculeViewProtocol
|
|
||||||
|
|
||||||
- (void)setAsMolecule {
|
- (void)setAsMolecule {
|
||||||
self.updateViewHorizontalDefaults = YES;
|
self.updateViewHorizontalDefaults = YES;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -55,7 +55,7 @@ extern NSString * _Nonnull const ConstraintWidth;
|
|||||||
+ (nullable NSDictionary *)constraintPinView:(nonnull UIView*)view heightConstraint:(BOOL)pinHeight heightConstant:(CGFloat)heightConstant widthConstraint:(BOOL)pinWidth widthConstant:(CGFloat)widthConstant;
|
+ (nullable NSDictionary *)constraintPinView:(nonnull UIView*)view heightConstraint:(BOOL)pinHeight heightConstant:(CGFloat)heightConstant widthConstraint:(BOOL)pinWidth widthConstant:(CGFloat)widthConstant;
|
||||||
|
|
||||||
// pins 2 views in same hierarchy
|
// pins 2 views in same hierarchy
|
||||||
+(nullable NSLayoutConstraint *)constraintPinFirstView :(nonnull UIView*)firstView toSecondView :(nonnull UIView*)secondView withConstant :(CGFloat)constant directionVertical :(BOOL)directionVertical;
|
+(nonnull NSLayoutConstraint *)constraintPinFirstView :(nonnull UIView*)firstView toSecondView :(nonnull UIView*)secondView withConstant :(CGFloat)constant directionVertical :(BOOL)directionVertical;
|
||||||
|
|
||||||
+(nullable NSDictionary *)constraintAlignView :(nonnull UIView *)firstView toSecondView :(nonnull UIView *)secondView alignX :(BOOL)alignX alignY :(BOOL)alignY;
|
+(nullable NSDictionary *)constraintAlignView :(nonnull UIView *)firstView toSecondView :(nonnull UIView *)secondView alignX :(BOOL)alignX alignY :(BOOL)alignY;
|
||||||
|
|
||||||
|
|||||||
@ -10,9 +10,6 @@ import UIKit
|
|||||||
|
|
||||||
@objcMembers open class ButtonView: ViewConstrainingView {
|
@objcMembers open class ButtonView: ViewConstrainingView {
|
||||||
open var primaryButton: PrimaryButton? = PrimaryButton.button()
|
open var primaryButton: PrimaryButton? = PrimaryButton.button()
|
||||||
open var alignCenterPin: NSLayoutConstraint?
|
|
||||||
open var alignCenterLeftPin: NSLayoutConstraint?
|
|
||||||
open var alignCenterRightPin: NSLayoutConstraint?
|
|
||||||
|
|
||||||
// MARK: - Inits
|
// MARK: - Inits
|
||||||
public init() {
|
public init() {
|
||||||
@ -53,7 +50,7 @@ import UIKit
|
|||||||
open override func setupView() {
|
open override func setupView() {
|
||||||
super.setupView()
|
super.setupView()
|
||||||
setupButton()
|
setupButton()
|
||||||
alignCenter()
|
alignCenterHorizontal()
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - MVMCoreUIMoleculeViewProtocol
|
// MARK: - MVMCoreUIMoleculeViewProtocol
|
||||||
@ -75,56 +72,9 @@ import UIKit
|
|||||||
func setupButton() {
|
func setupButton() {
|
||||||
if let primaryButton = primaryButton, !subviews.contains(primaryButton) {
|
if let primaryButton = primaryButton, !subviews.contains(primaryButton) {
|
||||||
addSubview(primaryButton)
|
addSubview(primaryButton)
|
||||||
setupConstraints(forView: primaryButton)
|
pinView(toSuperView: primaryButton)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupConstraints(forView view: UIView) {
|
|
||||||
leftPin = view.leftAnchor.constraint(equalTo: leftAnchor)
|
|
||||||
topPin = view.topAnchor.constraint(equalTo: topAnchor)
|
|
||||||
rightPin = rightAnchor.constraint(equalTo: view.rightAnchor)
|
|
||||||
bottomPin = bottomAnchor.constraint(equalTo: view.bottomAnchor)
|
|
||||||
leftPin?.isActive = true
|
|
||||||
topPin?.isActive = true
|
|
||||||
rightPin?.isActive = true
|
|
||||||
bottomPin?.isActive = true
|
|
||||||
|
|
||||||
alignCenterPin = view.centerXAnchor.constraint(equalTo: centerXAnchor)
|
|
||||||
alignCenterLeftPin = view.leftAnchor.constraint(greaterThanOrEqualTo: leftAnchor)
|
|
||||||
alignCenterRightPin = rightAnchor.constraint(greaterThanOrEqualTo: view.rightAnchor)
|
|
||||||
}
|
|
||||||
|
|
||||||
open func alignLeft() {
|
|
||||||
alignCenterPin?.isActive = false
|
|
||||||
alignCenterLeftPin?.isActive = false
|
|
||||||
alignCenterRightPin?.isActive = true
|
|
||||||
leftPin?.isActive = true
|
|
||||||
rightPin?.isActive = false
|
|
||||||
}
|
|
||||||
|
|
||||||
open func alignCenter() {
|
|
||||||
alignCenterPin?.isActive = true
|
|
||||||
alignCenterLeftPin?.isActive = true
|
|
||||||
alignCenterRightPin?.isActive = true
|
|
||||||
leftPin?.isActive = false
|
|
||||||
rightPin?.isActive = false
|
|
||||||
}
|
|
||||||
|
|
||||||
open func alignRight() {
|
|
||||||
alignCenterPin?.isActive = false
|
|
||||||
alignCenterLeftPin?.isActive = true
|
|
||||||
alignCenterRightPin?.isActive = false
|
|
||||||
leftPin?.isActive = false
|
|
||||||
rightPin?.isActive = true
|
|
||||||
}
|
|
||||||
|
|
||||||
open func alignFill() {
|
|
||||||
alignCenterPin?.isActive = false
|
|
||||||
alignCenterLeftPin?.isActive = false
|
|
||||||
alignCenterRightPin?.isActive = false
|
|
||||||
leftPin?.isActive = true
|
|
||||||
rightPin?.isActive = true
|
|
||||||
}
|
|
||||||
|
|
||||||
open override func setLeftPinConstant(_ constant: CGFloat) {
|
open override func setLeftPinConstant(_ constant: CGFloat) {
|
||||||
super.setLeftPinConstant(constant)
|
super.setLeftPinConstant(constant)
|
||||||
|
|||||||
@ -27,6 +27,9 @@
|
|||||||
/// For the molecule list to load more efficiently.
|
/// For the molecule list to load more efficiently.
|
||||||
+ (CGFloat)estimatedHeightForRow:(nullable NSDictionary *)json;
|
+ (CGFloat)estimatedHeightForRow:(nullable NSDictionary *)json;
|
||||||
|
|
||||||
|
/// Allows the molecule to set its name for reuse. Default could be moleculeName.
|
||||||
|
+ (nullable NSString *)nameForReuse:(nullable NSDictionary *)molecule delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -8,10 +8,82 @@
|
|||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
public class MoleculeStackView: MFView {
|
public class StackItem {
|
||||||
var spacingBlock: ((Any) -> UIEdgeInsets)?
|
var view: UIView
|
||||||
var moleculesArray: [UIView]?
|
var spacing: CGFloat?
|
||||||
var useMargins: Bool = false
|
var percentage: Int?
|
||||||
|
var verticalAlignment: UIStackView.Alignment?
|
||||||
|
var horizontalAlignment: UIStackView.Alignment?
|
||||||
|
|
||||||
|
init(with view: UIView) {
|
||||||
|
self.view = view
|
||||||
|
}
|
||||||
|
|
||||||
|
init(with view: UIView, json: [AnyHashable: Any]) {
|
||||||
|
self.view = view
|
||||||
|
update(with: json)
|
||||||
|
}
|
||||||
|
|
||||||
|
func update(with json: [AnyHashable: Any]) {
|
||||||
|
spacing = json.optionalCGFloatForKey("spacing")
|
||||||
|
percentage = json["percent"] as? Int
|
||||||
|
if let alignment = json.optionalStringForKey("verticalAlignment") {
|
||||||
|
verticalAlignment = ViewConstrainingView.getAlignmentFor(alignment, defaultAlignment: .fill)
|
||||||
|
}
|
||||||
|
if let alignment = json.optionalStringForKey("horizontalAlignment") {
|
||||||
|
horizontalAlignment = ViewConstrainingView.getAlignmentFor(alignment, defaultAlignment: .fill)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MoleculeStackView: ViewConstrainingView {
|
||||||
|
var contentView: UIView = MVMCoreUICommonViewsUtility.commonView()
|
||||||
|
var items: [StackItem] = []
|
||||||
|
|
||||||
|
/// For setting the direction of the stack
|
||||||
|
var axis: NSLayoutConstraint.Axis = .vertical {
|
||||||
|
didSet {
|
||||||
|
updateViewHorizontalDefaults = axis == .horizontal
|
||||||
|
if axis != oldValue {
|
||||||
|
restack()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The spacing to use between each item in the stack.
|
||||||
|
var spacing: CGFloat = 16 {
|
||||||
|
didSet {
|
||||||
|
if spacing != oldValue {
|
||||||
|
restack()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Helpers
|
||||||
|
public func setAxisWithJSON(_ json: [AnyHashable: Any]?) {
|
||||||
|
switch json?.optionalStringForKey("axis") {
|
||||||
|
case "horizontal":
|
||||||
|
axis = .horizontal
|
||||||
|
default:
|
||||||
|
axis = .vertical
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func pinView(_ view: UIView, toView: UIView, attribute: NSLayoutConstraint.Attribute, relation: NSLayoutConstraint.Relation, priority: UILayoutPriority, constant: CGFloat) {
|
||||||
|
let constraint = NSLayoutConstraint(item: view, attribute: attribute, relatedBy: relation, toItem: toView, attribute: attribute, multiplier: 1.0, constant: constant)
|
||||||
|
constraint.priority = priority
|
||||||
|
constraint.isActive = true
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Restacks the existing items.
|
||||||
|
func restack() {
|
||||||
|
MVMCoreUIStackableViewController.remove(contentView.subviews)
|
||||||
|
let stackItems = items
|
||||||
|
items.removeAll()
|
||||||
|
for (index, item) in stackItems.enumerated() {
|
||||||
|
addStackItem(item, lastItem: index == stackItems.count - 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - Inits
|
// MARK: - Inits
|
||||||
public override init(frame: CGRect) {
|
public override init(frame: CGRect) {
|
||||||
@ -23,11 +95,6 @@ public class MoleculeStackView: MFView {
|
|||||||
setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
|
setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
|
||||||
}
|
}
|
||||||
|
|
||||||
public convenience init(withJSON json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, spacingBlock: ((Any) -> UIEdgeInsets)?) {
|
|
||||||
self.init(withJSON: json, delegateObject: delegateObject, additionalData: nil)
|
|
||||||
self.spacingBlock = spacingBlock
|
|
||||||
}
|
|
||||||
|
|
||||||
public required init?(coder aDecoder: NSCoder) {
|
public required init?(coder aDecoder: NSCoder) {
|
||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
@ -35,47 +102,153 @@ public class MoleculeStackView: MFView {
|
|||||||
// MARK: - MFViewProtocol
|
// MARK: - MFViewProtocol
|
||||||
public override func setupView() {
|
public override func setupView() {
|
||||||
super.setupView()
|
super.setupView()
|
||||||
|
guard contentView.superview == nil else {
|
||||||
|
return
|
||||||
|
}
|
||||||
translatesAutoresizingMaskIntoConstraints = false
|
translatesAutoresizingMaskIntoConstraints = false
|
||||||
backgroundColor = .clear
|
backgroundColor = .clear
|
||||||
self.setContentHuggingPriority(UILayoutPriority.required, for: NSLayoutConstraint.Axis.vertical)
|
addConstrainedView(contentView)
|
||||||
self.setContentCompressionResistancePriority(UILayoutPriority.required, for: NSLayoutConstraint.Axis.vertical)
|
contentView.setContentHuggingPriority(.defaultHigh, for: .vertical)
|
||||||
|
contentView.setContentHuggingPriority(.defaultHigh, for: .horizontal)
|
||||||
}
|
}
|
||||||
|
|
||||||
public override func updateView(_ size: CGFloat) {
|
public override func updateView(_ size: CGFloat) {
|
||||||
super.updateView(size)
|
super.updateView(size)
|
||||||
for view in subviews {
|
for item in items {
|
||||||
if let mvmView = view as? MVMCoreViewProtocol {
|
(item.view as? MVMCoreViewProtocol)?.updateView(size)
|
||||||
mvmView.updateView(size)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - MVMCoreUIMoleculeViewProtocol
|
// MARK: - MVMCoreUIMoleculeViewProtocol
|
||||||
|
public override func setAsMolecule() {
|
||||||
|
updateViewHorizontalDefaults = false
|
||||||
|
}
|
||||||
|
|
||||||
|
public override func reset() {
|
||||||
|
backgroundColor = .clear
|
||||||
|
for item in items {
|
||||||
|
if let view = item.view as? MVMCoreUIMoleculeViewProtocol {
|
||||||
|
view.reset?()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
|
open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
|
||||||
|
let previousJSON = self.json
|
||||||
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
|
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
|
||||||
|
MVMCoreUIStackableViewController.remove(contentView.subviews)
|
||||||
|
|
||||||
|
// If the items in the stack are the same, just update previous items instead of re-allocating.
|
||||||
|
var items: [StackItem]?
|
||||||
|
if MoleculeStackView.name(forReuse: previousJSON, delegateObject: delegateObject) == MoleculeStackView.name(forReuse: json, delegateObject: delegateObject) {
|
||||||
|
items = self.items
|
||||||
|
}
|
||||||
|
self.items = []
|
||||||
|
|
||||||
|
if let colorString = json?.optionalStringForKey(KeyBackgroundColor) {
|
||||||
|
backgroundColor = .mfGet(forHex: colorString)
|
||||||
|
}
|
||||||
|
|
||||||
guard let molecules = json?.arrayForKey(KeyMolecules) as? [[String: Any]] else {
|
guard let molecules = json?.arrayForKey(KeyMolecules) as? [[String: Any]] else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the molecules and set the json.
|
// Sets the stack attributes
|
||||||
var moleculesArray = [] as [UIView]
|
setAxisWithJSON(json)
|
||||||
for moleculeJSON in molecules {
|
spacing = json?.optionalCGFloatForKey("spacing") ?? 16
|
||||||
if let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject, constrainIfNeeded: true) {
|
|
||||||
moleculesArray.append(molecule)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
guard moleculesArray.count > 0 else {
|
// Set the alignment for the stack in the containing view. The json driven value is for the axis direction alignment.
|
||||||
return
|
if axis == .vertical {
|
||||||
}
|
alignHorizontal(.fill)
|
||||||
|
alignVertical(ViewConstrainingView.getAlignmentFor(json?.optionalStringForKey("alignment"), defaultAlignment: .fill))
|
||||||
if let spacingBlock = spacingBlock {
|
|
||||||
MVMCoreUIStackableViewController.populateView(self, withUIArray: moleculesArray, useMargins: useMargins, withSpacingBlock: spacingBlock)
|
|
||||||
} else {
|
} else {
|
||||||
let separation = json?.optionalCGFloatForKey("separation") ?? PaddingDefault
|
alignHorizontal(ViewConstrainingView.getAlignmentFor(json?.optionalStringForKey("alignment"), defaultAlignment: .fill))
|
||||||
MVMCoreUIStackableViewController.populateView(self, withUIArray: moleculesArray, useMargins: useMargins) { (object) -> UIEdgeInsets in
|
alignVertical(.leading)
|
||||||
return UIEdgeInsets.init(top: separation, left: 0, bottom: 0, right: 0)
|
}
|
||||||
|
|
||||||
|
// Adds the molecules and sets the json.
|
||||||
|
for (index, map) in molecules.enumerated() {
|
||||||
|
if let moleculeJSON = map.optionalDictionaryForKey(KeyMolecule) {
|
||||||
|
var view: UIView?
|
||||||
|
if let item = items?[index] {
|
||||||
|
(item.view as? MVMCoreUIMoleculeViewProtocol)?.setWithJSON(moleculeJSON, delegateObject: delegateObject, additionalData: additionalData)
|
||||||
|
item.update(with: moleculeJSON)
|
||||||
|
view = item.view
|
||||||
|
addStackItem(item, lastItem: index == molecules.count - 1)
|
||||||
|
} else if let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject, constrainIfNeeded: true) {
|
||||||
|
view = molecule
|
||||||
|
addStackItem(StackItem(with: molecule, json: map), lastItem: index == molecules.count - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
(view as? MVMCoreUIViewConstrainingProtocol)?.shouldSetHorizontalMargins?(axis == .vertical)
|
||||||
|
(view as? MVMCoreUIViewConstrainingProtocol)?.shouldSetVerticalMargins?(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override static func name(forReuse molecule: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> String? {
|
||||||
|
// This will aggregate names of molecules to make an id.
|
||||||
|
var name = ""
|
||||||
|
guard let molecules = molecule?.optionalArrayForKey(KeyMolecules) else {
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
for case let item as [AnyHashable: AnyHashable] in molecules {
|
||||||
|
if let moleculeName = item.stringOptionalWithChainOfKeysOrIndexes([KeyMolecule, KeyMoleculeName]) {
|
||||||
|
name.append(moleculeName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Adding to stack
|
||||||
|
/// Adds the view to the stack.
|
||||||
|
func addView(_ view: UIView, lastItem: Bool) {
|
||||||
|
addStackItem(StackItem(with: view), lastItem: lastItem)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds the stack item to the stack.
|
||||||
|
func addStackItem(_ stackItem: StackItem, lastItem: Bool) {
|
||||||
|
let view = stackItem.view
|
||||||
|
contentView.addSubview(view)
|
||||||
|
view.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
|
||||||
|
let spacing = stackItem.spacing ?? self.spacing
|
||||||
|
if let view = view as? MVMCoreUIViewConstrainingProtocol {
|
||||||
|
let verticalAlignment = stackItem.verticalAlignment ?? (stackItem.percentage == nil && axis == .vertical ? .fill : (axis == .vertical ? .leading : .center))
|
||||||
|
let horizontalAlignment = stackItem.horizontalAlignment ?? view.alignment?() ?? (axis == .vertical || stackItem.percentage == nil ? .fill : .leading)
|
||||||
|
view.alignHorizontal?(horizontalAlignment)
|
||||||
|
view.alignVertical?(verticalAlignment)
|
||||||
|
}
|
||||||
|
if axis == .vertical {
|
||||||
|
if items.count == 0 {
|
||||||
|
pinView(view, toView: contentView, attribute: .top, relation: .equal, priority: .required, constant: spacing)
|
||||||
|
} else if let previousView = items.last?.view {
|
||||||
|
_ = NSLayoutConstraint(pinFirstView: previousView, toSecondView: view, withConstant: spacing, directionVertical: true)
|
||||||
|
}
|
||||||
|
pinView(view, toView: contentView, attribute: .leading, relation: .equal, priority: .required, constant: 0)
|
||||||
|
pinView(contentView, toView: view, attribute: .trailing, relation: .equal, priority: .required, constant: 0)
|
||||||
|
if let percent = stackItem.percentage {
|
||||||
|
view.heightAnchor.constraint(equalTo: contentView.heightAnchor, multiplier: CGFloat(percent)/100.0).isActive = true
|
||||||
|
}
|
||||||
|
if lastItem {
|
||||||
|
pinView(contentView, toView: view, attribute: .bottom, relation: .equal, priority: .required, constant: 0)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if items.count == 0 {
|
||||||
|
// First horizontal item has no spacing by default unless told otherwise.
|
||||||
|
pinView(view, toView: contentView, attribute: .leading, relation: .equal, priority: .required, constant: stackItem.spacing ?? 0)
|
||||||
|
} else if let previousView = items.last?.view {
|
||||||
|
_ = NSLayoutConstraint(pinFirstView: previousView, toSecondView: view, withConstant: spacing, directionVertical: false)
|
||||||
|
}
|
||||||
|
pinView(view, toView: contentView, attribute: .top, relation: .equal, priority: .required, constant: 0)
|
||||||
|
pinView(contentView, toView: view, attribute: .bottom, relation: .equal, priority: .required, constant: 0)
|
||||||
|
if let percent = stackItem.percentage {
|
||||||
|
view.widthAnchor.constraint(equalTo: contentView.widthAnchor, multiplier: CGFloat(percent)/100.0).isActive = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if lastItem {
|
||||||
|
pinView(contentView, toView: view, attribute: .right, relation: .equal, priority: .required, constant: 0)
|
||||||
|
}
|
||||||
|
items.append(stackItem)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -43,11 +43,25 @@ import UIKit
|
|||||||
public func updateView(_ size: CGFloat) {
|
public func updateView(_ size: CGFloat) {
|
||||||
MFStyler.setDefaultMarginsFor(self, size: size, horizontal: true, vertical: true)
|
MFStyler.setDefaultMarginsFor(self, size: size, horizontal: true, vertical: true)
|
||||||
if #available(iOS 11.0, *) {
|
if #available(iOS 11.0, *) {
|
||||||
contentView.directionalLayoutMargins = directionalLayoutMargins
|
if accessoryView != nil {
|
||||||
|
// Smaller left margin if accessory view.
|
||||||
|
var margin = directionalLayoutMargins
|
||||||
|
margin.trailing = 16
|
||||||
|
contentView.directionalLayoutMargins = margin
|
||||||
|
} else {
|
||||||
|
contentView.directionalLayoutMargins = directionalLayoutMargins
|
||||||
|
}
|
||||||
topSeparatorView?.setLeftAndRightPinConstant(directionalLayoutMargins.leading)
|
topSeparatorView?.setLeftAndRightPinConstant(directionalLayoutMargins.leading)
|
||||||
bottomSeparatorView?.setLeftAndRightPinConstant(directionalLayoutMargins.leading)
|
bottomSeparatorView?.setLeftAndRightPinConstant(directionalLayoutMargins.leading)
|
||||||
} else {
|
} else {
|
||||||
contentView.layoutMargins = layoutMargins
|
if accessoryView != nil {
|
||||||
|
// Smaller left margin if accessory view.
|
||||||
|
var margin = layoutMargins
|
||||||
|
margin.right = 16
|
||||||
|
contentView.layoutMargins = margin
|
||||||
|
} else {
|
||||||
|
contentView.layoutMargins = layoutMargins
|
||||||
|
}
|
||||||
topSeparatorView?.setLeftAndRightPinConstant(layoutMargins.left)
|
topSeparatorView?.setLeftAndRightPinConstant(layoutMargins.left)
|
||||||
bottomSeparatorView?.setLeftAndRightPinConstant(layoutMargins.left)
|
bottomSeparatorView?.setLeftAndRightPinConstant(layoutMargins.left)
|
||||||
}
|
}
|
||||||
@ -67,7 +81,7 @@ import UIKit
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - MVMCoreUIMoleculeViewProtocol
|
// MARK: - MVMCoreUIMoleculeViewProtocol
|
||||||
public func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) {
|
public func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
|
||||||
self.json = json;
|
self.json = json;
|
||||||
guard let json = json, let moleculeJSON = json.optionalDictionaryForKey(KeyMolecule) else {
|
guard let json = json, let moleculeJSON = json.optionalDictionaryForKey(KeyMolecule) else {
|
||||||
return
|
return
|
||||||
@ -75,15 +89,17 @@ import UIKit
|
|||||||
if molecule == nil {
|
if molecule == nil {
|
||||||
if let moleculeView = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject, constrainIfNeeded: true) {
|
if let moleculeView = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject, constrainIfNeeded: true) {
|
||||||
contentView.addSubview(moleculeView)
|
contentView.addSubview(moleculeView)
|
||||||
let standardConstraints = (moleculeView as? MVMCoreUIViewConstrainingProtocol)?.useStandardConstraints?() ?? true
|
var standardConstraints = true
|
||||||
|
if let castView = moleculeView as? MVMCoreUIViewConstrainingProtocol {
|
||||||
|
standardConstraints = castView.useStandardConstraints?() ?? true
|
||||||
|
castView.shouldSetHorizontalMargins?(!standardConstraints)
|
||||||
|
castView.shouldSetVerticalMargins?(!standardConstraints)
|
||||||
|
}
|
||||||
NSLayoutConstraint.activate(Array(NSLayoutConstraint.pinView(toSuperview: moleculeView, useMargins: standardConstraints).values))
|
NSLayoutConstraint.activate(Array(NSLayoutConstraint.pinView(toSuperview: moleculeView, useMargins: standardConstraints).values))
|
||||||
if standardConstraints {
|
if standardConstraints {
|
||||||
let constraint = contentView.heightAnchor.constraint(equalToConstant: 80)
|
let constraint = contentView.heightAnchor.constraint(equalToConstant: 80)
|
||||||
constraint.priority = .defaultLow
|
constraint.priority = .defaultLow
|
||||||
constraint.isActive = true
|
constraint.isActive = true
|
||||||
if let moleculeView = moleculeView as? ViewConstrainingView {
|
|
||||||
moleculeView.updateViewHorizontalDefaults = false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
molecule = moleculeView
|
molecule = moleculeView
|
||||||
}
|
}
|
||||||
@ -110,15 +126,27 @@ import UIKit
|
|||||||
molecule?.reset?()
|
molecule?.reset?()
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func estimatedHeight(forRow json: [AnyHashable : Any]?) -> CGFloat {
|
public static func estimatedHeight(forRow json: [AnyHashable: Any]?) -> CGFloat {
|
||||||
guard let moleculeJSON = json?.optionalDictionaryForKey(KeyMolecule),
|
guard let moleculeJSON = json?.optionalDictionaryForKey(KeyMolecule),
|
||||||
let theClass = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: moleculeJSON, delegateObject: nil),
|
let theClass = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: moleculeJSON, delegateObject: nil),
|
||||||
let estimatedHeightFor = theClass.estimatedHeight else {
|
let estimatedHeightFor = theClass.estimatedHeight else {
|
||||||
return 0
|
return 80
|
||||||
}
|
}
|
||||||
return estimatedHeightFor(moleculeJSON)
|
return estimatedHeightFor(moleculeJSON)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static func name(forReuse molecule: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> String? {
|
||||||
|
if let molecule = molecule?.optionalDictionaryForKey(KeyMolecule),
|
||||||
|
let moleculeName = molecule.optionalStringForKey(KeyMoleculeName),
|
||||||
|
let moleculeClass = MVMCoreUIMoleculeMappingObject.shared()?.moleculeMapping[moleculeName] as? AnyClass,
|
||||||
|
let castClass = moleculeClass as? MVMCoreUIMoleculeViewProtocol.Type,
|
||||||
|
let nameFunc = castClass.name {
|
||||||
|
return nameFunc(molecule, delegateObject)
|
||||||
|
} else {
|
||||||
|
return molecule?.optionalDictionaryForKey(KeyMolecule)?.optionalStringForKey(KeyMoleculeName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - Arrow
|
// MARK: - Arrow
|
||||||
/// Adds the standard mvm style caret to the accessory view
|
/// Adds the standard mvm style caret to the accessory view
|
||||||
public func addCaretViewAccessory() {
|
public func addCaretViewAccessory() {
|
||||||
@ -129,16 +157,12 @@ import UIKit
|
|||||||
let height: CGFloat = 10
|
let height: CGFloat = 10
|
||||||
caretView = CaretView(lineThickness: CaretView.thin)
|
caretView = CaretView(lineThickness: CaretView.thin)
|
||||||
caretView?.frame = CGRect(x: 0, y: 0, width: width, height: height)
|
caretView?.frame = CGRect(x: 0, y: 0, width: width, height: height)
|
||||||
caretViewWidthSizeObject = MFSizeObject(scalingStandardSize: width)
|
caretViewWidthSizeObject = MFSizeObject(standardSize: width, standardiPadPortraitSize: 9)
|
||||||
caretViewHeightSizeObject = MFSizeObject(scalingStandardSize: height)
|
caretViewHeightSizeObject = MFSizeObject(standardSize: height, standardiPadPortraitSize: 16)
|
||||||
accessoryView = caretView
|
accessoryView = caretView
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - MoleculeListCellProtocol
|
// MARK: - MoleculeListCellProtocol
|
||||||
public static func moleculeName(_ molecule: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> String? {
|
|
||||||
return molecule?.optionalDictionaryForKey(KeyMolecule)?.optionalStringForKey(KeyMoleculeName)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// For when the separator between cells shows using json and frequency. Default is type: standard, frequency: allExceptTop.
|
/// For when the separator between cells shows using json and frequency. Default is type: standard, frequency: allExceptTop.
|
||||||
public func setSeparatorWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?, indexPath: IndexPath) {
|
public func setSeparatorWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?, indexPath: IndexPath) {
|
||||||
addSeparatorsIfNeeded()
|
addSeparatorsIfNeeded()
|
||||||
@ -155,7 +179,7 @@ import UIKit
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func didSelectCell(atIndex indexPath: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) {
|
public func didSelectCell(atIndex indexPath: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
|
||||||
if let actionMap = json?.optionalDictionaryForKey("actionMap") {
|
if let actionMap = json?.optionalDictionaryForKey("actionMap") {
|
||||||
MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegateObject: delegateObject)
|
MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegateObject: delegateObject)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
@objcMembers public class ProgressBarView: ViewConstrainingView {
|
@objcMembers public class ProgressBarWithLabel: ViewConstrainingView {
|
||||||
|
|
||||||
var progress = ProgressBar()
|
var progress = ProgressBar()
|
||||||
var topleftlabel = Label()
|
var topleftlabel = Label()
|
||||||
@ -22,7 +22,8 @@ import UIKit
|
|||||||
|
|
||||||
open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
|
open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
|
||||||
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
|
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
|
||||||
progress.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
|
let progressbarjson = json?.optionalDictionaryForKey("progressbar")
|
||||||
|
progress.setWithJSON(progressbarjson, delegateObject: delegateObject, additionalData: additionalData)
|
||||||
|
|
||||||
let topleftlabeljson = json?.optionalDictionaryForKey("label")
|
let topleftlabeljson = json?.optionalDictionaryForKey("label")
|
||||||
let toprightlabeljson = json?.optionalDictionaryForKey("toprightlabel")
|
let toprightlabeljson = json?.optionalDictionaryForKey("toprightlabel")
|
||||||
@ -68,7 +68,6 @@ public class StandardHeaderView: ViewConstrainingView {
|
|||||||
|
|
||||||
if let separatorView = SeparatorView.separatorAdd(to: self, position: SeparatorPositionBot, withHorizontalPadding: 0) {
|
if let separatorView = SeparatorView.separatorAdd(to: self, position: SeparatorPositionBot, withHorizontalPadding: 0) {
|
||||||
separatorView.setAsHeavy()
|
separatorView.setAsHeavy()
|
||||||
separatorView.isHidden = true
|
|
||||||
addSubview(separatorView)
|
addSubview(separatorView)
|
||||||
self.separatorView = separatorView
|
self.separatorView = separatorView
|
||||||
}
|
}
|
||||||
|
|||||||
@ -44,8 +44,8 @@ import UIKit
|
|||||||
if let backgroundColorString = json?.optionalStringForKey(KeyBackgroundColor) {
|
if let backgroundColorString = json?.optionalStringForKey(KeyBackgroundColor) {
|
||||||
backgroundColor = UIColor.mfGet(forHex: backgroundColorString)
|
backgroundColor = UIColor.mfGet(forHex: backgroundColorString)
|
||||||
}
|
}
|
||||||
let primaryButtonMap = json?.optionalDictionaryForKey("primaryButton")
|
let primaryButtonMap = json?.optionalDictionaryForKey(KeyPrimaryButton)
|
||||||
let secondaryButtonMap = json?.optionalDictionaryForKey("secondaryButton")
|
let secondaryButtonMap = json?.optionalDictionaryForKey(KeySecondaryButton)
|
||||||
set(primaryButtonJSON: primaryButtonMap, secondaryButtonJSON: secondaryButtonMap, delegateObject: delegateObject, additionalData: additionalData)
|
set(primaryButtonJSON: primaryButtonMap, secondaryButtonJSON: secondaryButtonMap, delegateObject: delegateObject, additionalData: additionalData)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,8 +103,8 @@ import UIKit
|
|||||||
addSubview(viewForButtons)
|
addSubview(viewForButtons)
|
||||||
self.viewForButtons = viewForButtons
|
self.viewForButtons = viewForButtons
|
||||||
|
|
||||||
setupConstraints(forView: viewForButtons)
|
pinView(toSuperView: viewForButtons)
|
||||||
alignCenter()
|
alignCenterHorizontal()
|
||||||
|
|
||||||
createPrimaryButton()
|
createPrimaryButton()
|
||||||
createSecondaryButton()
|
createSecondaryButton()
|
||||||
@ -118,8 +118,8 @@ import UIKit
|
|||||||
createPrimaryButton()
|
createPrimaryButton()
|
||||||
if let primaryButton = primaryButton {
|
if let primaryButton = primaryButton {
|
||||||
addSubview(primaryButton)
|
addSubview(primaryButton)
|
||||||
setupConstraints(forView: primaryButton)
|
pinView(toSuperView: primaryButton)
|
||||||
alignCenter()
|
alignCenterHorizontal()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -36,14 +36,15 @@
|
|||||||
@"caretButton": CaretButton.class,
|
@"caretButton": CaretButton.class,
|
||||||
@"textField" : MFTextField.class,
|
@"textField" : MFTextField.class,
|
||||||
@"checkbox" : MVMCoreUICheckBox.class,
|
@"checkbox" : MVMCoreUICheckBox.class,
|
||||||
@"progressBarView" : ProgressBarView.class,
|
@"progressBarWithLabel" : ProgressBarWithLabel.class,
|
||||||
@"progressBar": ProgressBar.class,
|
@"progressBar": ProgressBar.class,
|
||||||
@"textField": MFTextField.class,
|
@"textField": MFTextField.class,
|
||||||
@"checkbox": MVMCoreUICheckBox.class,
|
@"checkbox": MVMCoreUICheckBox.class,
|
||||||
@"radioButton": RadioButton.class,
|
@"radioButton": RadioButton.class,
|
||||||
@"listItem": MoleculeTableViewCell.class,
|
@"listItem": MoleculeTableViewCell.class,
|
||||||
@"switchLineItem": SwitchLineItem.class,
|
@"switchLineItem": SwitchLineItem.class,
|
||||||
@"switch": Switch.class
|
@"switch": Switch.class,
|
||||||
|
@"leftRightLabelView": LeftRightLabelView.class
|
||||||
} mutableCopy];
|
} mutableCopy];
|
||||||
});
|
});
|
||||||
return mapping;
|
return mapping;
|
||||||
|
|||||||
@ -21,4 +21,14 @@
|
|||||||
/// Can be used to override any standard constraints that may be added.
|
/// Can be used to override any standard constraints that may be added.
|
||||||
- (BOOL)useStandardConstraints;
|
- (BOOL)useStandardConstraints;
|
||||||
|
|
||||||
|
/// Will align if it can.
|
||||||
|
- (void)alignHorizontal:(UIStackViewAlignment)alignment;
|
||||||
|
- (void)alignVertical:(UIStackViewAlignment)alignment;
|
||||||
|
|
||||||
|
/// Containing Views can tell the contained if they should use horizontal margins.
|
||||||
|
- (void)shouldSetHorizontalMargins:(BOOL)shouldSet;
|
||||||
|
|
||||||
|
/// Containing Views can tell the contained if they should use vertical margins.
|
||||||
|
- (void)shouldSetVerticalMargins:(BOOL)shouldSet;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@ -208,6 +208,9 @@ B3 -> Legal
|
|||||||
|
|
||||||
#pragma mark - 2.0 styles
|
#pragma mark - 2.0 styles
|
||||||
|
|
||||||
|
/// Will style the label based on the string. Accepted values, H1, H2, H3, H32, B1, B2, B3, B20
|
||||||
|
+ (void)styleLabel:(nonnull UILabel *)label withStyle:(nullable NSString *)style;
|
||||||
|
|
||||||
+ (void)styleLabelH1:(nonnull UILabel *)label genericScaling:(BOOL)genericScaling;
|
+ (void)styleLabelH1:(nonnull UILabel *)label genericScaling:(BOOL)genericScaling;
|
||||||
+ (void)styleLabelH1:(nonnull UILabel *)label;
|
+ (void)styleLabelH1:(nonnull UILabel *)label;
|
||||||
|
|
||||||
@ -253,6 +256,9 @@ B3 -> Legal
|
|||||||
|
|
||||||
#pragma mark - Attributed Strings
|
#pragma mark - Attributed Strings
|
||||||
|
|
||||||
|
/// Will style the string based on the string. Accepted values, H1, H2, H3, H32, B1, B2, B3, B20
|
||||||
|
+ (nonnull NSAttributedString *)styleGetAttributedString:(nullable NSString *)string withStyle:(nullable NSString *)style;
|
||||||
|
|
||||||
+ (nonnull NSAttributedString *)styleGetAttributedString:(nullable NSString *)string font:(nonnull UIFont *)font color:(nonnull UIColor *)color;
|
+ (nonnull NSAttributedString *)styleGetAttributedString:(nullable NSString *)string font:(nonnull UIFont *)font color:(nonnull UIColor *)color;
|
||||||
+ (nonnull NSAttributedString *)styleGetH1AttributedString:(nullable NSString *)string;
|
+ (nonnull NSAttributedString *)styleGetH1AttributedString:(nullable NSString *)string;
|
||||||
+ (nonnull NSAttributedString *)styleGetH2AttributedString:(nullable NSString *)string;
|
+ (nonnull NSAttributedString *)styleGetH2AttributedString:(nullable NSString *)string;
|
||||||
|
|||||||
@ -512,6 +512,26 @@ CGFloat const LabelWithInternalButtonLineSpace = 2;
|
|||||||
|
|
||||||
#pragma mark - 2.0 Styles
|
#pragma mark - 2.0 Styles
|
||||||
|
|
||||||
|
+ (void)styleLabel:(nonnull UILabel *)label withStyle:(nullable NSString *)style {
|
||||||
|
if ([style isEqualToString:@"H1"]) {
|
||||||
|
[self styleLabelH1:label];
|
||||||
|
} else if ([style isEqualToString:@"H2"]) {
|
||||||
|
[self styleLabelH2:label];
|
||||||
|
} else if ([style isEqualToString:@"H3"]) {
|
||||||
|
[self styleLabelH3:label];
|
||||||
|
} else if ([style isEqualToString:@"H32"]) {
|
||||||
|
[self styleLabelH32:label];
|
||||||
|
} else if ([style isEqualToString:@"B1"]) {
|
||||||
|
[self styleLabelB1:label];
|
||||||
|
} else if ([style isEqualToString:@"B3"]) {
|
||||||
|
[self styleLabelB3:label];
|
||||||
|
} else if ([style isEqualToString:@"B20"]) {
|
||||||
|
[self styleLabelB20:label];
|
||||||
|
} else {
|
||||||
|
[self styleLabelB2:label];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
+ (void)styleLabelH1:(nonnull UILabel *)label genericScaling:(BOOL)genericScaling {
|
+ (void)styleLabelH1:(nonnull UILabel *)label genericScaling:(BOOL)genericScaling {
|
||||||
label.font = [MFStyler fontH1:genericScaling];
|
label.font = [MFStyler fontH1:genericScaling];
|
||||||
label.textColor = [UIColor blackColor];
|
label.textColor = [UIColor blackColor];
|
||||||
@ -631,6 +651,26 @@ CGFloat const LabelWithInternalButtonLineSpace = 2;
|
|||||||
|
|
||||||
#pragma mark - Attributed Strings
|
#pragma mark - Attributed Strings
|
||||||
|
|
||||||
|
+ (nonnull NSAttributedString *)styleGetAttributedString:(nullable NSString *)string withStyle:(nullable NSString *)style {
|
||||||
|
if ([style isEqualToString:@"H1"]) {
|
||||||
|
return [self styleGetH1AttributedString:string];
|
||||||
|
} else if ([style isEqualToString:@"H2"]) {
|
||||||
|
return [self styleGetH2AttributedString:string];
|
||||||
|
} else if ([style isEqualToString:@"H3"]) {
|
||||||
|
return [self styleGetH3AttributedString:string];
|
||||||
|
} else if ([style isEqualToString:@"H32"]) {
|
||||||
|
return [self styleGetH32AttributedString:string];
|
||||||
|
} else if ([style isEqualToString:@"B1"]) {
|
||||||
|
return [self styleGetB1AttributedString:string];
|
||||||
|
} else if ([style isEqualToString:@"B3"]) {
|
||||||
|
return [self styleGetB3AttributedString:string];
|
||||||
|
} else if ([style isEqualToString:@"B20"]) {
|
||||||
|
return [self styleGetB20AttributedString:string];
|
||||||
|
} else {
|
||||||
|
return [self styleGetB2AttributedString:string];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
+ (nonnull NSAttributedString *)styleGetAttributedString:(nullable NSString *)string font:(nonnull UIFont *)font color:(nonnull UIColor *)color {
|
+ (nonnull NSAttributedString *)styleGetAttributedString:(nullable NSString *)string font:(nonnull UIFont *)font color:(nonnull UIColor *)color {
|
||||||
NSAttributedString *attributedString = nil;
|
NSAttributedString *attributedString = nil;
|
||||||
if (![string isEqual:[NSNull null]] && string.length > 0) {
|
if (![string isEqual:[NSNull null]] && string.length > 0) {
|
||||||
@ -657,6 +697,10 @@ CGFloat const LabelWithInternalButtonLineSpace = 2;
|
|||||||
return [MFStyler styleGetAttributedString:string font:[MFStyler fontH3] color:[UIColor blackColor]];
|
return [MFStyler styleGetAttributedString:string font:[MFStyler fontH3] color:[UIColor blackColor]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+ (nonnull NSAttributedString *)styleGetH32AttributedString:(nullable NSString *)string {
|
||||||
|
return [MFStyler styleGetAttributedString:string font:[MFStyler fontH32] color:[UIColor blackColor]];
|
||||||
|
}
|
||||||
|
|
||||||
+ (nonnull NSAttributedString *)styleGetB1AttributedString:(nullable NSString *)string {
|
+ (nonnull NSAttributedString *)styleGetB1AttributedString:(nullable NSString *)string {
|
||||||
return [MFStyler styleGetAttributedString:string font:[MFStyler fontB1] color:[UIColor blackColor]];
|
return [MFStyler styleGetAttributedString:string font:[MFStyler fontB1] color:[UIColor blackColor]];
|
||||||
}
|
}
|
||||||
@ -669,6 +713,10 @@ CGFloat const LabelWithInternalButtonLineSpace = 2;
|
|||||||
return [MFStyler styleGetAttributedString:string font:[MFStyler fontB3] color:[UIColor mfBattleshipGrey]];
|
return [MFStyler styleGetAttributedString:string font:[MFStyler fontB3] color:[UIColor mfBattleshipGrey]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+ (nonnull NSAttributedString *)styleGetB20AttributedString:(nullable NSString *)string {
|
||||||
|
return [MFStyler styleGetAttributedString:string font:[MFStyler fontB20] color:[UIColor blackColor]];
|
||||||
|
}
|
||||||
|
|
||||||
+ (nonnull NSAttributedString *)styleGetDisabledB1AttributedString:(nullable NSString *)string {
|
+ (nonnull NSAttributedString *)styleGetDisabledB1AttributedString:(nullable NSString *)string {
|
||||||
return [MFStyler styleGetAttributedString:string font:[MFStyler fontB1] color:[UIColor mfLighterGrayColor]];
|
return [MFStyler styleGetAttributedString:string font:[MFStyler fontB1] color:[UIColor mfLighterGrayColor]];
|
||||||
}
|
}
|
||||||
|
|||||||
108
MVMCoreUI/Styles/usage.json
Normal file
108
MVMCoreUI/Styles/usage.json
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
{
|
||||||
|
"pageType": "usage",
|
||||||
|
"template": "moleculeList",
|
||||||
|
"header": {
|
||||||
|
"moleculeName":"header",
|
||||||
|
"headline":{
|
||||||
|
"moleculeName": "label",
|
||||||
|
"text":"See who's using what."
|
||||||
|
},
|
||||||
|
"body":{
|
||||||
|
"moleculeName": "label",
|
||||||
|
"text":"Data usage was estimated as of Jun 11."
|
||||||
|
},
|
||||||
|
"molecules": [{
|
||||||
|
"moleculeName": "listItem",
|
||||||
|
"molecule" : {
|
||||||
|
"moleculeName":"moleculeStack",
|
||||||
|
"axis": "horizontal",
|
||||||
|
"molecules": [{
|
||||||
|
"percent": 60,
|
||||||
|
"molecule": {
|
||||||
|
"moleculeName": "label",
|
||||||
|
"text": "Johny Verizon\n555.555.5555\nGo Unlimited",
|
||||||
|
"attributes": [{
|
||||||
|
"location": 0,
|
||||||
|
"length": 13,
|
||||||
|
"type": "font",
|
||||||
|
"style": "B1"
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"horizontalAlignment": "trailing",
|
||||||
|
"molecule": {
|
||||||
|
"moleculeName": "label",
|
||||||
|
"text": "4.55 GB"
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
"actionMap":{
|
||||||
|
"actionType": "openPage",
|
||||||
|
"pageType": "usageDetails",
|
||||||
|
"extraParameters": {
|
||||||
|
"mdn": "5555555555"
|
||||||
|
}
|
||||||
|
}},{
|
||||||
|
"moleculeName": "listItem",
|
||||||
|
"molecule" : {
|
||||||
|
"moleculeName":"moleculeStack",
|
||||||
|
"axis": "horizontal",
|
||||||
|
"molecules": [{
|
||||||
|
"percent": 60,
|
||||||
|
"molecule": {
|
||||||
|
"moleculeName": "label",
|
||||||
|
"text": "Sree Verizon\n555.555.5556",
|
||||||
|
"attributes": [{
|
||||||
|
"location": 0,
|
||||||
|
"length": 12,
|
||||||
|
"type": "font",
|
||||||
|
"style": "B1"
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"horizontalAlignment": "trailing",
|
||||||
|
"molecule": {
|
||||||
|
"moleculeName": "label",
|
||||||
|
"text": "0 GB"
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
"actionMap":{
|
||||||
|
"actionType": "openPage",
|
||||||
|
"pageType": "usageDetails",
|
||||||
|
"extraParameters": {
|
||||||
|
"mdn": "5555555556"
|
||||||
|
}
|
||||||
|
}},{
|
||||||
|
"moleculeName": "listItem",
|
||||||
|
"molecule" : {
|
||||||
|
"moleculeName":"moleculeStack",
|
||||||
|
"axis": "horizontal",
|
||||||
|
"molecules": [{
|
||||||
|
"percent": 60,
|
||||||
|
"molecule": {
|
||||||
|
"moleculeName": "label",
|
||||||
|
"text": "Vishal Verizon\n555.555.5557\nGo Unlimited",
|
||||||
|
"attributes": [{
|
||||||
|
"location": 0,
|
||||||
|
"length": 14,
|
||||||
|
"type": "font",
|
||||||
|
"style": "B1"
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"horizontalAlignment": "trailing",
|
||||||
|
"molecule": {
|
||||||
|
"moleculeName": "label",
|
||||||
|
"text": "0 GB"
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
"actionMap":{
|
||||||
|
"actionType": "openPage",
|
||||||
|
"pageType": "usageDetails",
|
||||||
|
"extraParameters": {
|
||||||
|
"mdn": "5555555557"
|
||||||
|
}
|
||||||
|
}}]
|
||||||
|
}
|
||||||
@ -10,8 +10,6 @@
|
|||||||
|
|
||||||
@protocol MoleculeListCellProtocol <NSObject>
|
@protocol MoleculeListCellProtocol <NSObject>
|
||||||
@optional
|
@optional
|
||||||
/// Can override the molecule name for the given molecule. Otherwise we assume value for key moleculeName.
|
|
||||||
+ (nullable NSString *)moleculeName:(nullable NSDictionary *)molecule delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject;
|
|
||||||
|
|
||||||
/// Can set the separator according to what the moleculeList commands.
|
/// Can set the separator according to what the moleculeList commands.
|
||||||
- (void)setSeparatorWithJSON:(nullable NSDictionary *)json delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject additionalData:(nullable NSDictionary *)additionalData indexPath:(nonnull NSIndexPath *)indexPath;
|
- (void)setSeparatorWithJSON:(nullable NSDictionary *)json delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject additionalData:(nullable NSDictionary *)additionalData indexPath:(nonnull NSIndexPath *)indexPath;
|
||||||
|
|||||||
@ -36,7 +36,7 @@ open class MoleculeListTemplate: ThreeLayerTableViewController {
|
|||||||
override open func viewForBottom() -> UIView {
|
override open func viewForBottom() -> UIView {
|
||||||
guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("footer"),
|
guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("footer"),
|
||||||
let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject() as? MVMCoreUIDelegateObject, constrainIfNeeded: true) else {
|
let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject() as? MVMCoreUIDelegateObject, constrainIfNeeded: true) else {
|
||||||
return viewForBottom()
|
return super.viewForBottom()
|
||||||
}
|
}
|
||||||
return molecule
|
return molecule
|
||||||
}
|
}
|
||||||
@ -117,7 +117,7 @@ open class MoleculeListTemplate: ThreeLayerTableViewController {
|
|||||||
guard let map = molecule.molecule, let moleculeName = map.optionalStringForKey(KeyMoleculeName), let moleculeClass = MVMCoreUIMoleculeMappingObject.shared()?.moleculeMapping[moleculeName] as? AnyClass else {
|
guard let map = molecule.molecule, let moleculeName = map.optionalStringForKey(KeyMoleculeName), let moleculeClass = MVMCoreUIMoleculeMappingObject.shared()?.moleculeMapping[moleculeName] as? AnyClass else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if let moleculeClass = moleculeClass as? MoleculeListCellProtocol.Type, let moleculeNameFunc = moleculeClass.moleculeName {
|
if let moleculeClass = moleculeClass as? MVMCoreUIMoleculeViewProtocol.Type, let moleculeNameFunc = moleculeClass.name {
|
||||||
return (moleculeNameFunc(map, delegateObject() as? MVMCoreUIDelegateObject), moleculeClass)
|
return (moleculeNameFunc(map, delegateObject() as? MVMCoreUIDelegateObject), moleculeClass)
|
||||||
} else {
|
} else {
|
||||||
return (moleculeName, moleculeClass)
|
return (moleculeName, moleculeClass)
|
||||||
|
|||||||
@ -197,7 +197,13 @@ static const CGFloat VertialShadowOffset = 6;
|
|||||||
[view.rightAnchor constraintEqualToAnchor:button.rightAnchor constant:PaddingTwo].active = YES;
|
[view.rightAnchor constraintEqualToAnchor:button.rightAnchor constant:PaddingTwo].active = YES;
|
||||||
[view.centerYAnchor constraintEqualToAnchor:button.centerYAnchor].active = YES;
|
[view.centerYAnchor constraintEqualToAnchor:button.centerYAnchor].active = YES;
|
||||||
} else {
|
} else {
|
||||||
[NSLayoutConstraint constraintPinSubview:button pinTop:YES topConstant:PaddingOne pinBottom:NO bottomConstant:0 pinLeft:NO leftConstant:0 pinRight:YES rightConstant:PaddingTwo];
|
if (@available(iOS 11.0, *)) {
|
||||||
|
[button.topAnchor constraintEqualToAnchor:view.safeAreaLayoutGuide.topAnchor constant:PaddingOne].active = YES;
|
||||||
|
[view.safeAreaLayoutGuide.trailingAnchor constraintEqualToAnchor:button.trailingAnchor constant:PaddingTwo].active = YES;
|
||||||
|
} else {
|
||||||
|
[NSLayoutConstraint constraintPinSubview:button pinTop:YES topConstant:PaddingOne pinBottom:NO bottomConstant:0 pinLeft:NO leftConstant:0 pinRight:YES rightConstant:PaddingTwo];
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return button;
|
return button;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user