This commit is contained in:
Suresh, Kamlesh 2019-08-27 12:13:48 -04:00
commit 0f1ea89623
40 changed files with 874 additions and 223 deletions

View File

@ -20,8 +20,9 @@
01DF55E021F8FAA800CC099B /* MFTextFieldListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01DF55DF21F8FAA800CC099B /* MFTextFieldListView.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, ); }; };
0A1214A022C11A18007C7030 /* ActionDetailWithImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A12149F22C11A17007C7030 /* ActionDetailWithImage.swift */; };
B8200E152280C4CF007245F4 /* ProgressBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8200E142280C4CF007245F4 /* ProgressBar.swift */; };
B8200E192281DC1A007245F4 /* ProgressBarWithLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8200E182281DC1A007245F4 /* ProgressBarWithLabel.swift */; };
B8200E192281DC1A007245F4 /* CornerLabels.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8200E182281DC1A007245F4 /* CornerLabels.swift */; };
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 */; };
D20A9A5E2243D3E300ADE781 /* TwoButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20A9A5D2243D3E300ADE781 /* TwoButtonView.swift */; };
@ -169,8 +170,11 @@
D2A638FD22CA98280052ED1F /* HeadlineBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2A638FC22CA98280052ED1F /* HeadlineBody.swift */; };
D2A6390122CBB1820052ED1F /* Carousel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2A6390022CBB1820052ED1F /* Carousel.swift */; };
D2A6390522CBCE160052ED1F /* MoleculeCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2A6390422CBCE160052ED1F /* MoleculeCollectionViewCell.swift */; };
D2B1E3E522F37D6A0065F95C /* ImageHeadlineBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2B1E3E422F37D6A0065F95C /* ImageHeadlineBody.swift */; };
D2C5001821F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.h in Headers */ = {isa = PBXBuildFile; fileRef = D2C5001621F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.h */; settings = {ATTRIBUTES = (Public, ); }; };
D2C5001921F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m in Sources */ = {isa = PBXBuildFile; fileRef = D2C5001721F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m */; };
D2D6CD4022E78C1A00D701B8 /* Scroller.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2D6CD3F22E78C1A00D701B8 /* Scroller.swift */; };
D2D6CD4222E78FAB00D701B8 /* ThreeLayerTemplate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2D6CD4122E78FAB00D701B8 /* ThreeLayerTemplate.swift */; };
D2E1FADB2260D3D200AEFD8C /* MVMCoreUIDelegateObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2E1FADA2260D3D200AEFD8C /* MVMCoreUIDelegateObject.swift */; };
D2E1FADD2268B25E00AEFD8C /* MoleculeTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2E1FADC2268B25E00AEFD8C /* MoleculeTableViewCell.swift */; };
D2E1FADF2268B8E700AEFD8C /* ThreeLayerTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2E1FADE2268B8E700AEFD8C /* ThreeLayerTableViewController.swift */; };
@ -196,8 +200,9 @@
01CA51B4229716F60071A6EE /* Switch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Switch.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>"; };
0A12149F22C11A17007C7030 /* ActionDetailWithImage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionDetailWithImage.swift; sourceTree = "<group>"; };
B8200E142280C4CF007245F4 /* ProgressBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressBar.swift; sourceTree = "<group>"; };
B8200E182281DC1A007245F4 /* ProgressBarWithLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressBarWithLabel.swift; sourceTree = "<group>"; };
B8200E182281DC1A007245F4 /* CornerLabels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CornerLabels.swift; 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>"; };
D20A9A5D2243D3E300ADE781 /* TwoButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TwoButtonView.swift; sourceTree = "<group>"; };
@ -349,8 +354,11 @@
D2A638FC22CA98280052ED1F /* HeadlineBody.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadlineBody.swift; sourceTree = "<group>"; };
D2A6390022CBB1820052ED1F /* Carousel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Carousel.swift; sourceTree = "<group>"; };
D2A6390422CBCE160052ED1F /* MoleculeCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeCollectionViewCell.swift; sourceTree = "<group>"; };
D2B1E3E422F37D6A0065F95C /* ImageHeadlineBody.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageHeadlineBody.swift; sourceTree = "<group>"; };
D2C5001621F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreUIViewControllerMappingObject.h; sourceTree = "<group>"; };
D2C5001721F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MVMCoreUIViewControllerMappingObject.m; sourceTree = "<group>"; };
D2D6CD3F22E78C1A00D701B8 /* Scroller.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Scroller.swift; sourceTree = "<group>"; };
D2D6CD4122E78FAB00D701B8 /* ThreeLayerTemplate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreeLayerTemplate.swift; sourceTree = "<group>"; };
D2E1FADA2260D3D200AEFD8C /* MVMCoreUIDelegateObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MVMCoreUIDelegateObject.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>"; };
@ -447,6 +455,7 @@
D2A514622213643100345BFB /* MoleculeStackCenteredTemplate.swift */,
D296E13B2295969C0051EBE7 /* MoleculeListCellProtocol.h */,
D2E1FAE02268E81D00AEFD8C /* MoleculeListTemplate.swift */,
D2D6CD4122E78FAB00D701B8 /* ThreeLayerTemplate.swift */,
);
path = Templates;
sourceTree = "<group>";
@ -473,6 +482,7 @@
D29DF10E21E67A77003B2FB9 /* Molecules */ = {
isa = PBXGroup;
children = (
0A12149F22C11A17007C7030 /* ActionDetailWithImage.swift */,
01DF55DF21F8FAA800CC099B /* MFTextFieldListView.swift */,
D29770C721F7C4AE00B2F0D0 /* TopLabelsView.h */,
D29770C621F7C4AE00B2F0D0 /* TopLabelsView.m */,
@ -490,6 +500,7 @@
B8200E182281DC1A007245F4 /* ProgressBarWithLabel.swift */,
B8200E182281DC1A007245F4 /* ProgressBarView.swift */,
0116A4E4228B19640094F3ED /* RadioButtonModel.swift */,
B8200E182281DC1A007245F4 /* CornerLabels.swift */,
D29B770F22C281F400D6ACE0 /* ModuleMolecule.swift */,
D2A638FC22CA98280052ED1F /* HeadlineBody.swift */,
D2A6390022CBB1820052ED1F /* Carousel.swift */,
@ -497,6 +508,8 @@
D260D7AF22D65BDD007E7233 /* MVMCoreUIPageControl.h */,
D260D7B022D65BDD007E7233 /* MVMCoreUIPageControl.m */,
D260D7B522D68509007E7233 /* MVMCoreUIPagingProtocol.h */,
D2D6CD3F22E78C1A00D701B8 /* Scroller.swift */,
D2B1E3E422F37D6A0065F95C /* ImageHeadlineBody.swift */,
);
path = Molecules;
sourceTree = "<group>";
@ -958,12 +971,14 @@
D282AABA224131D100C46919 /* MFTransparentGIFView.swift in Sources */,
D2A514672213885800345BFB /* StandardHeaderView.swift in Sources */,
DBEFFA04225A829700230692 /* Label.swift in Sources */,
D2D6CD4022E78C1A00D701B8 /* Scroller.swift in Sources */,
D29DF13021E6851E003B2FB9 /* MVMCoreUITopAlertShortView.m in Sources */,
D28B4F8B21FF967C00712C7A /* MVMCoreUIObject.m in Sources */,
D260D7B222D65BDD007E7233 /* MVMCoreUIPageControl.m in Sources */,
D29DF26D21E6AA0B003B2FB9 /* FLAnimatedImageView.m in Sources */,
D29DF2EF21ECEAE1003B2FB9 /* MFFonts.m in Sources */,
D282AACB2243C61700C46919 /* ButtonView.swift in Sources */,
D2D6CD4222E78FAB00D701B8 /* ThreeLayerTemplate.swift in Sources */,
0105618F224BBE7700E1557D /* FormValidator+FormParams.swift in Sources */,
D2E1FADD2268B25E00AEFD8C /* MoleculeTableViewCell.swift in Sources */,
D29DF2AE21E7B3A4003B2FB9 /* MFTextView.m in Sources */,
@ -996,6 +1011,7 @@
D29770C821F7C4AE00B2F0D0 /* TopLabelsView.m in Sources */,
D2E1FADF2268B8E700AEFD8C /* ThreeLayerTableViewController.swift in Sources */,
D20A9A5E2243D3E300ADE781 /* TwoButtonView.swift in Sources */,
D2B1E3E522F37D6A0065F95C /* ImageHeadlineBody.swift in Sources */,
D29DF2AA21E7B2F9003B2FB9 /* MVMCoreUIConstants.m in Sources */,
D2A5146122121FBF00345BFB /* MoleculeStackTemplate.swift in Sources */,
D29DF11821E6805F003B2FB9 /* NSLayoutConstraint+MFConvenience.m in Sources */,
@ -1008,11 +1024,12 @@
D29DF13221E6851E003B2FB9 /* MVMCoreUITopAlertBaseView.m in Sources */,
D29DF29C21E7ADB9003B2FB9 /* MFProgrammaticTableViewController.m in Sources */,
0105618E224BBE7700E1557D /* FormValidator+TextFields.swift in Sources */,
0A1214A022C11A18007C7030 /* ActionDetailWithImage.swift in Sources */,
D29DF2BE21E7BEA4003B2FB9 /* TopTabbar.m in Sources */,
D2A514632213643100345BFB /* MoleculeStackCenteredTemplate.swift in Sources */,
D29DF32421ED0DA2003B2FB9 /* TextButtonView.m in Sources */,
D29DF29E21E7AE3B003B2FB9 /* MFStyler.m in Sources */,
B8200E192281DC1A007245F4 /* ProgressBarWithLabel.swift in Sources */,
B8200E192281DC1A007245F4 /* CornerLabels.swift in Sources */,
D2A514592211C53C00345BFB /* MVMCoreUIMoleculeMappingObject.m in Sources */,
0105618D224BBE7700E1557D /* FormValidator.swift in Sources */,
D22D1F1B220341F60077CEC0 /* MVMCoreUICheckBox.m in Sources */,

View File

@ -178,6 +178,17 @@ public typealias ActionBlock = () -> Void
setLabel(label, withHTML: json?.optionalStringForKey("html"))
if let alignment = json?.optionalStringForKey("textAlignment") {
switch alignment {
case "center":
label.textAlignment = .center
case "right":
label.textAlignment = .right
default:
label.textAlignment = .left
}
}
if let backgroundColorHex = json?.optionalStringForKey(KeyBackgroundColor), !backgroundColorHex.isEmpty {
label.backgroundColor = UIColor.mfGet(forHex: backgroundColorHex)
}
@ -217,7 +228,7 @@ public typealias ActionBlock = () -> Void
case "strikethrough":
attributedString.addAttribute(.strikethroughStyle, value: NSUnderlineStyle.thick.rawValue, range: range)
attributedString.addAttribute(.baselineOffset, value: 0, range: range)
case "color":
if let colorHex = attribute.optionalStringForKey(KeyTextColor), !colorHex.isEmpty {
attributedString.removeAttribute(.foregroundColor, range: range)
@ -368,6 +379,7 @@ extension Label {
public func reset() {
text = nil
attributedText = nil
textAlignment = .left
originalAttributedString = nil
styleB2(true)
}

View File

@ -22,9 +22,11 @@ import UIKit
var imageWidth: CGFloat?
var imageHeight: CGFloat?
var delegateObject: MVMCoreUIDelegateObject?
// For keeping track of current state.
private var edges: UIRectEdge?
private var spinnerHeight: CGFloat?
private var edges = UIRectEdge(rawValue: 0)
private var spinnerHeight: CGFloat = 0
private var currentImageWidth: CGFloat?
private var currentImageHeight: CGFloat?
private var currentImageName: String?
@ -37,7 +39,6 @@ import UIKit
// The default is an image that is centered with no edges pinned. So it will take the size of the content and fill as needed.
public init() {
edges = UIRectEdge(rawValue: 0)
super.init(frame: .zero)
}
@ -91,10 +92,7 @@ import UIKit
pinView(toSuperView: imageView)
// Setup edges constraints
if edges == nil {
edges = UIRectEdge(rawValue: 0)
}
pinEdges(edges!)
pinEdges(edges)
// Setup spinner.
loadingSpinner.clipsToBounds = true
@ -153,6 +151,40 @@ import UIKit
return false
}
// MARK: - Constraints
func setHeight(_ height: CGFloat) {
if let heightConstraint = heightConstraint, MVMCoreGetterUtility.cgfequal(heightConstraint.multiplier, 1) {
heightConstraint.constant = height
} else {
heightConstraint?.isActive = false
heightConstraint = imageView.heightAnchor.constraint(equalToConstant: height)
heightConstraint?.priority = UILayoutPriority(rawValue: 900)
}
heightConstraint?.isActive = true
}
func setWidth(_ width: CGFloat) {
if let widthConstraint = widthConstraint, MVMCoreGetterUtility.cgfequal(widthConstraint.multiplier, 1) {
widthConstraint.constant = width
} else {
widthConstraint = imageView.widthAnchor.constraint(equalToConstant: width)
widthConstraint?.priority = UILayoutPriority(rawValue: 900)
}
widthConstraint?.isActive = true
}
func layoutWillChange(width: CGFloat?, height: CGFloat?, size: CGSize?) -> Bool {
guard addSizeConstraintsForAspectRatio else {
return false
}
let widthWillChange = !MVMCoreGetterUtility.cgfequal(widthConstraint?.constant ?? 0, width ?? 0)
let heightWillChange = !MVMCoreGetterUtility.cgfequal(heightConstraint?.constant ?? 0, height ?? 0)
let sizeWillChange = (width == nil || height == nil) && !(size?.equalTo(imageView.image?.size ?? CGSize.zero) ?? false)
let heightChangeFromSpinner = ((height ?? size?.height) ?? 0) < loadingSpinnerHeightConstraint?.constant ?? CGFloat.leastNormalMagnitude
return widthWillChange || heightWillChange || sizeWillChange || heightChangeFromSpinner
}
// Constrains the image view to be the size provided. Used to size it to the image to fix aspect fit defect.
func addConstraints(width: NSNumber?, height: NSNumber?, size: CGSize?) {
widthConstraint?.isActive = false
@ -162,26 +194,25 @@ import UIKit
}
if let width = width, let height = height {
heightConstraint = imageView.heightAnchor.constraint(equalToConstant: height.cgfloat())
widthConstraint = imageView.widthAnchor.constraint(equalToConstant: width.cgfloat())
setHeight(height.cgfloat())
setWidth(width.cgfloat())
} else if let width = width, let size = size {
widthConstraint = imageView.widthAnchor.constraint(equalToConstant: width.cgfloat())
setWidth(width.cgfloat())
heightConstraint = imageView.heightAnchor.constraint(equalTo: imageView.widthAnchor, multiplier: size.height/size.width)
heightConstraint?.priority = UILayoutPriority(rawValue: 900)
heightConstraint?.isActive = true
} else if let height = height, let size = size {
heightConstraint = imageView.heightAnchor.constraint(equalToConstant: height.cgfloat())
setHeight(height.cgfloat())
widthConstraint = imageView.widthAnchor.constraint(equalTo: imageView.heightAnchor, multiplier: size.width/size.height)
widthConstraint?.priority = UILayoutPriority(rawValue: 900)
widthConstraint?.isActive = true
}
widthConstraint?.priority = UILayoutPriority(rawValue: 900)
heightConstraint?.priority = UILayoutPriority(rawValue: 900)
heightConstraint?.isActive = true
widthConstraint?.isActive = true
imageView.setContentHuggingPriority(UILayoutPriority.defaultLow, for: NSLayoutConstraint.Axis.horizontal)
imageView.setContentHuggingPriority(UILayoutPriority.defaultLow, for: NSLayoutConstraint.Axis.vertical)
}
// MARK: - MVMCoreUIMoleculeViewProtocol functions
open override func setAsMolecule() {
addSizeConstraintsForAspectRatio = true
pinEdges(.all)
}
public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
@ -190,6 +221,7 @@ import UIKit
open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
self.delegateObject = delegateObject
if let accessibilityString = json?.optionalStringForKey("accessibilityText") {
imageView.accessibilityLabel = accessibilityString
imageView.accessibilityTraits = .staticText
@ -197,6 +229,13 @@ import UIKit
}
let width = json?.optionalCGFloatForKey("width") ?? imageWidth
let height = json?.optionalCGFloatForKey("height") ?? imageHeight
// For smoother transitions, set constraints that we know immediately.
if let width = width, addSizeConstraintsForAspectRatio {
setWidth(width)
}
if let height = height, addSizeConstraintsForAspectRatio {
setHeight(height)
}
if let imageName = json?.optionalStringForKey("image"), shouldLoadImage(withName: imageName, width: width, height: height) {
imageView.image = nil
imageView.animatedImage = nil
@ -210,9 +249,9 @@ import UIKit
self.currentImageName = imageName
self.currentImageWidth = width?.cgfloat()
self.currentImageHeight = height?.cgfloat()
self.loadingSpinner.resumeSpinnerAfterDelay()
if let height = self.spinnerHeight {
self.loadingSpinnerHeightConstraint?.constant = height
if MVMCoreCache.isHostedImage(imageName) {
self.loadingSpinner.resumeSpinnerAfterDelay()
self.loadingSpinnerHeightConstraint?.constant = self.spinnerHeight
}
let finishedLoadingBlock: MVMCoreGetImageBlock = {[weak self] (image, data, isFallbackImage) in MVMCoreDispatchUtility.performBlock(onMainThread: { [weak self] in
@ -220,9 +259,13 @@ import UIKit
return
}
self?.isFallbackImage = isFallbackImage
self?.loadingSpinnerHeightConstraint?.constant = 0
self?.loadingSpinner.pause()
let layoutWillChange = self?.layoutWillChange(width: self?.currentImageWidth, height: self?.currentImageHeight, size: image?.size) ?? false
self?.addConstraints(width: width, height: height, size: image?.size)
self?.loadingSpinnerHeightConstraint?.constant = 0
if layoutWillChange {
self?.delegateObject?.moleculeDelegate?.moleculeLayoutUpdated?(self!)
}
completionHandler(image,data,isFallbackImage)
})}
@ -241,9 +284,8 @@ import UIKit
MVMCoreDispatchUtility.performBlock(onMainThread: { [unowned self] in
self.currentImageName = imageName
self.loadingSpinner.resumeSpinnerAfterDelay()
if let height = self.spinnerHeight {
self.loadingSpinnerHeightConstraint?.constant = height
}
self.loadingSpinnerHeightConstraint?.constant = self.spinnerHeight
MVMCoreCache.shared()?.getCroppedImage(imageName, useWidth: width != nil, widthForS7: width?.intValue ?? 0, useHeight: height != nil, heightForS7: height?.intValue ?? 0, finalRect: cropRect, flipImage: flipImage, localFallbackImageName: customFallbackImage ?? MVMCoreUIUtility.localizedImageName("fallback"), completionHandler: { [weak self] (image, data, isFallBackImage) in
MVMCoreDispatchUtility.performBlock(onMainThread: {
guard let image = image, let loadingImageName = self?.currentImageName, loadingImageName == imageName else {

View File

@ -30,7 +30,6 @@ typedef void (^PerformActionForRadioButton)(void);
@property (nullable, copy, nonatomic) PerformActionForRadioButton performActionForCheck;
typedef void (^CircleSelectedClosure)(_Nonnull id sender);
@property (nonatomic, strong, nullable) UIColor* fillColor;
@property (nonatomic, strong, nullable) UIColor* borderColor;
@property (nonatomic) CGFloat circleBorderWidth;
@ -38,11 +37,16 @@ typedef void (^CircleSelectedClosure)(_Nonnull id sender);
@property (nonatomic, copy, nullable) CircleSelectedClosure handleSelectionBlock;
@property (nonatomic) CGFloat circleDiameter;
@property (nonatomic, nullable, strong, readonly) CAShapeLayer * myCircle;
@property (nullable, weak, nonatomic) UIView *outerCircleView;
@property (nullable, weak, nonatomic) UIView *innerCircleView;
@property (nonatomic, strong, nullable) NSLayoutConstraint *heightConstraint;
@property (nonatomic, strong, nullable) NSLayoutConstraint *widthConstraint;
@property (nonatomic) BOOL respondsToTapGesture;
@property (nonatomic, getter = isSelected) BOOL selected;
@property (strong, nonatomic) NSLayoutConstraint *innerHeightConstarint;
@property (strong, nonatomic) NSLayoutConstraint *innerWidthConstarint;
@property (strong, nonatomic) NSLayoutConstraint *outerHeightConstarint;
@property (strong, nonatomic) NSLayoutConstraint *outerWidthConstarint;
// Set line width manually
- (void)setCheckMarkLineWidth:(CGFloat)lineWidth;

View File

@ -12,11 +12,6 @@
static CGFloat const DefaultOuterCircleSize = 31;
static CGFloat const DefaultInnerCircleSize = 19;
@interface MFRadioButton ()
@property (nullable, weak, nonatomic) UIView *outerCircleView;
@property (nullable, weak, nonatomic) UIView *innerCircleView;
@end
@implementation MFRadioButton
@ -64,9 +59,11 @@ static CGFloat const DefaultInnerCircleSize = 19;
[outerCircleView.leftAnchor constraintEqualToAnchor:self.leftAnchor].active = YES;
[outerCircleView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor].active = YES;
[outerCircleView.rightAnchor constraintEqualToAnchor:self.rightAnchor].active = YES;
[outerCircleView.widthAnchor constraintEqualToConstant:DefaultOuterCircleSize].active = YES;
[outerCircleView.heightAnchor constraintEqualToConstant:DefaultOuterCircleSize].active = YES;
self.outerHeightConstarint = [outerCircleView.widthAnchor constraintEqualToConstant:DefaultOuterCircleSize];
self.outerHeightConstarint.active = YES;
self.outerWidthConstarint = [outerCircleView.heightAnchor constraintEqualToConstant:DefaultOuterCircleSize];
self.outerWidthConstarint.active = YES;
UIView *innerCircleView = [[UIView alloc] init];
[outerCircleView addSubview:innerCircleView];
@ -76,8 +73,11 @@ static CGFloat const DefaultInnerCircleSize = 19;
[innerCircleView.centerXAnchor constraintEqualToAnchor:outerCircleView.centerXAnchor].active = YES;
[innerCircleView.centerYAnchor constraintEqualToAnchor:outerCircleView.centerYAnchor].active = YES;
[innerCircleView.widthAnchor constraintEqualToConstant:DefaultInnerCircleSize].active = YES;
[innerCircleView.heightAnchor constraintEqualToConstant:DefaultInnerCircleSize].active = YES;
self.innerHeightConstarint = [innerCircleView.heightAnchor constraintEqualToConstant:DefaultInnerCircleSize];
self.innerHeightConstarint.active = YES;
self.innerWidthConstarint = [innerCircleView.widthAnchor constraintEqualToConstant:DefaultInnerCircleSize];
self.innerWidthConstarint.active = YES;
outerCircleView.userInteractionEnabled = NO;
innerCircleView.userInteractionEnabled = NO;

View File

@ -46,6 +46,13 @@
#pragma mark - MVMCoreUIMoleculeViewProtocol
- (void)setAsMolecule {
self.translatesAutoresizingMaskIntoConstraints = NO;
if (@available(iOS 11.0, *)) {
self.insetsLayoutMarginsFromSafeArea = NO;
}
}
- (void)reset {
self.backgroundColor = [UIColor clearColor];
}

View File

@ -114,6 +114,11 @@
} else {
self.hidden = YES;
}
NSString *colorString = [json string:KeyBackgroundColor];
if (colorString) {
self.backgroundColor = [UIColor mfGetColorForHex:colorString];
}
}
#pragma mark - helper

View File

@ -73,6 +73,9 @@
// Add a view to be constrained in this view.
- (void)addConstrainedView:(nonnull UIView *)view;
/// Can override to change how the molecule is added when shouldSetupMoleculeFromJSON = true. Inserts the molecule at 0 and calls pinToSuperView.
- (void)addMolecule:(nonnull UIView *)molecule;
// Change the alignment of the label
- (void)alignLeft;
- (void)alignCenterHorizontal;

View File

@ -241,6 +241,11 @@
}
}
- (void)addMolecule:(nonnull UIView *)molecule {
[self insertSubview:molecule atIndex:0];
[self pinViewToSuperView:molecule];
}
#pragma mark - MVMCoreUIViewConstrainingProtocol
- (void)alignHorizontal:(UIStackViewAlignment)alignment {
@ -307,6 +312,9 @@
if ([self.constrainedView respondsToSelector:@selector(updateView:)]) {
[((id<MVMCoreViewProtocol>)self.constrainedView) updateView:size];
}
if (self.molecule != self.constrainedView) {
[self.molecule updateView:size];
}
[MFStyler setDefaultMarginsForView:self size:size horizontal:self.updateViewHorizontalDefaults vertical:self.updateViewVerticalDefaults];
UIEdgeInsets margins = [MVMCoreUIUtility getMarginsForView:self];
if (self.updateViewHorizontalDefaults) {
@ -333,6 +341,7 @@
}
- (void)reset {
[super reset];
self.updateViewHorizontalDefaults = NO;
self.updateViewVerticalDefaults = NO;
if ([self.molecule respondsToSelector:@selector(alignment)]) {
@ -344,24 +353,24 @@
}
}
- (void)setAsMolecule {
}
- (void)setWithJSON:(NSDictionary *)json delegateObject:(MVMCoreUIDelegateObject *)delegateObject additionalData:(NSDictionary *)additionalData {
[super setWithJSON:json delegateObject:delegateObject additionalData:additionalData];
[self.molecule setWithJSON:json delegateObject:delegateObject additionalData:additionalData];
if (self.shouldSetupMoleculeFromJSON && !self.molecule) {
if (self.shouldSetupMoleculeFromJSON) {
NSDictionary *moleculeJSON = [json dict:KeyMolecule];
if (moleculeJSON) {
if (self.molecule) {
[self.molecule setWithJSON:moleculeJSON delegateObject:delegateObject additionalData:additionalData];
} else if (moleculeJSON) {
UIView <MVMCoreUIMoleculeViewProtocol>*molecule = [[MVMCoreUIMoleculeMappingObject sharedMappingObject] createMoleculeForJSON:moleculeJSON delegateObject:delegateObject constrainIfNeeded:true];
if (molecule) {
[self insertSubview:molecule atIndex:0];
[self pinViewToSuperView:molecule];
[self addMolecule:molecule];
}
self.molecule = molecule;
[self setMoleculeAccessibility];
}
[self setMoleculeAccessibility];
} else {
[self.molecule setWithJSON:json delegateObject:delegateObject additionalData:additionalData];
}
NSNumber *useHorizontalMargins = [json optionalNumberForKey:@"useHorizontalMargins"];

View File

@ -61,6 +61,9 @@
tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
tableView.delegate = self;
tableView.dataSource = self;
if (@available(iOS 11.0, *)) {
tableView.insetsContentViewsToSafeArea = NO;
}
if ([tableView respondsToSelector:@selector(setCellLayoutMarginsFollowReadableWidth:)]) {
tableView.cellLayoutMarginsFollowReadableWidth = NO;
}

View File

@ -21,23 +21,21 @@ open class ThreeLayerTableViewController: MFProgrammaticTableViewController {
private var topViewBottomConstraint: NSLayoutConstraint?
private var bottomViewTopConstraint: NSLayoutConstraint?
//MARK: - MVMCoreViewProtocol
//MARK: - MFViewController
open override func updateViews() {
super.updateViews()
let width = view.bounds.width
MFStyler.setDefaultMarginsFor(contentView, size: width)
if let topView = topView as? MVMCoreViewProtocol {
topView.updateView(width)
showHeader()
showHeader(width)
}
if let bottomView = bottomView as? MVMCoreViewProtocol {
bottomView.updateView(width)
showFooter()
showFooter(width)
}
self.tableView?.reloadData()
}
//MARK: - MFViewController
open override func newDataBuildScreen() {
super.newDataBuildScreen()
createViewForTableHeader()
@ -103,14 +101,15 @@ open class ThreeLayerTableViewController: MFProgrammaticTableViewController {
currentSpaceForCompare = currentSpace * 2;
}
let width = view.bounds.width
if !MVMCoreGetterUtility.cgfequalwiththreshold(newSpace, currentSpaceForCompare, 0.1) {
if fillTop && fillBottom {
// space both
let half = newSpace / 2
topViewBottomConstraint?.constant = half
bottomViewTopConstraint?.constant = half
showHeader()
showFooter()
showHeader(width)
showFooter(width)
} else if fillTop {
// Only top is spaced (half the size if the bottom view is out of the scroll because it needs to be sized as if there are two spacers but there is only one.
if bottomViewOutsideOfScrollArea {
@ -118,11 +117,11 @@ open class ThreeLayerTableViewController: MFProgrammaticTableViewController {
} else {
topViewBottomConstraint?.constant = newSpace
}
showHeader()
showHeader(width)
} else if fillBottom {
// Only bottom is spaced.
bottomViewTopConstraint?.constant = newSpace
showFooter()
showFooter(width)
}
}
}
@ -141,7 +140,7 @@ open class ThreeLayerTableViewController: MFProgrammaticTableViewController {
topViewBottomConstraint = headerView.bottomAnchor.constraint(equalTo: topView.bottomAnchor, constant: spaceBelowTopView() ?? 0)
topViewBottomConstraint?.isActive = true
self.headerView = headerView
showHeader()
showHeader(nil)
}
/// Gets the bottom view and adds it to a spacing view, footerView, and then calls showFooter.
@ -157,11 +156,11 @@ open class ThreeLayerTableViewController: MFProgrammaticTableViewController {
footerView.rightAnchor.constraint(equalTo: bottomView.rightAnchor).isActive = true
footerView.bottomAnchor.constraint(equalTo: bottomView.bottomAnchor).isActive = true
self.footerView = footerView
showFooter()
showFooter(nil)
}
/// Takes the current headerView and adds it to the tableHeaderView
func showHeader() {
func showHeader(_ sizingWidth: CGFloat?) {
headerView?.removeFromSuperview()
tableView?.tableHeaderView = nil
guard let headerView = headerView else {
@ -177,7 +176,7 @@ open class ThreeLayerTableViewController: MFProgrammaticTableViewController {
}
/// Takes the current footerView and adds it to the tableFooterView
func showFooter() {
func showFooter(_ sizingWidth: CGFloat?) {
footerView?.removeFromSuperview()
safeAreaView?.removeFromSuperview()
guard let footerView = footerView, let tableView = tableView else {

View File

@ -22,7 +22,7 @@ open class ThreeLayerViewController: ProgrammaticScrollViewController {
var bottomViewOutsideOfScroll = false
private var safeAreaView: UIView?
private var heightConstraint: NSLayoutConstraint?
var heightConstraint: NSLayoutConstraint?
open override func updateViews() {
super.updateViews()

View File

@ -303,8 +303,9 @@
}
- (void)addViewToContentView:(UIView *)bottomView {
self.bottomConstraint.active = YES;
if (![self bottomViewOutsideOfScroll]) {
self.bottomConstraint.active = YES;
}
// Buttons will be at the bottom of the content view.
[self.contentView addSubview:bottomView];

View File

@ -0,0 +1,186 @@
//
// ActionDetailWithImage.swift
// MVMCoreUI
//
// Created by Christiano, Kevin on 6/20/19.
// Copyright © 2019 Verizon Wireless. All rights reserved.
//
import UIKit
@objcMembers open class ActionDetailWithImage: ViewConstrainingView {
//------------------------------------------------------
// MARK: - Outlets
//------------------------------------------------------
let title = Label.commonLabelH3(true)
let message = Label.commonLabelB3(true)
let button = PrimaryButton.primaryTinyButton(false)!
let imageLoader = MFLoadImageView(pinnedEdges: .all)
let leftContainer = ViewConstrainingView.empty()
//------------------------------------------------------
// MARK: - Properties
//------------------------------------------------------
var bottomTitlePadding: CGFloat = PaddingOne
//------------------------------------------------------
// MARK: - Constraints
//------------------------------------------------------
var imageLeadingConstraint: NSLayoutConstraint?
var buttonTopConstraint: NSLayoutConstraint?
var messageTopConstraint: 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: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
self.init()
setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
}
//------------------------------------------------------
// MARK: - View Lifecycle
//------------------------------------------------------
override open func setupView() {
super.setupView()
guard subviews.isEmpty else { return }
setDefaultState()
addSubview(leftContainer)
addSubview(imageLoader)
leftContainer.addSubview(title)
leftContainer.addSubview(message)
leftContainer.addSubview(button)
leftContainer.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor).isActive = true
leftContainer.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor).isActive = true
layoutMarginsGuide.bottomAnchor.constraint(greaterThanOrEqualTo: leftContainer.bottomAnchor).isActive = true
let leftContainerBottom = leftContainer.bottomAnchor.constraint(equalTo: bottomAnchor)
leftContainerBottom.priority = UILayoutPriority(249)
leftContainerBottom.isActive = true
title.topAnchor.constraint(equalTo: leftContainer.topAnchor).isActive = true
title.leadingAnchor.constraint(equalTo: leftContainer.leadingAnchor).isActive = true
leftContainer.trailingAnchor.constraint(equalTo: title.trailingAnchor).isActive = true
messageTopConstraint = message.topAnchor.constraint(equalTo: title.bottomAnchor, constant: PaddingOne)
messageTopConstraint?.isActive = true
message.leadingAnchor.constraint(equalTo: leftContainer.leadingAnchor).isActive = true
leftContainer.trailingAnchor.constraint(equalTo: message.trailingAnchor).isActive = true
buttonTopConstraint = button.topAnchor.constraint(equalTo: message.bottomAnchor, constant: PaddingTwo)
buttonTopConstraint?.isActive = true
button.leadingAnchor.constraint(equalTo: leftContainer.leadingAnchor).isActive = true
leftContainer.bottomAnchor.constraint(equalTo: button.bottomAnchor).isActive = true
leftContainer.trailingAnchor.constraint(greaterThanOrEqualTo: button.trailingAnchor).isActive = true
imageLoader.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
layoutMarginsGuide.trailingAnchor.constraint(equalTo: imageLoader.trailingAnchor).isActive = true
imageLeadingConstraint = imageLoader.leadingAnchor.constraint(greaterThanOrEqualTo: leftContainer.trailingAnchor, constant: 16)
imageLeadingConstraint?.isActive = true
imageLoader.topAnchor.constraint(greaterThanOrEqualTo: layoutMarginsGuide.topAnchor).isActive = true
layoutMarginsGuide.bottomAnchor.constraint(greaterThanOrEqualTo: imageLoader.bottomAnchor).isActive = true
let imageloaderBottom = imageLoader.bottomAnchor.constraint(equalTo: layoutMarginsGuide.bottomAnchor)
imageloaderBottom.priority = UILayoutPriority(249)
imageloaderBottom.isActive = true
}
override open func updateView(_ size: CGFloat) {
super.updateView(size)
title.updateView(size)
message.updateView(size)
button.updateView(size)
imageLoader.updateView(size)
leftContainer.updateView(size)
messageTopConstraint?.constant = title.hasText && message.hasText ? bottomTitlePadding : 0
buttonTopConstraint?.constant = message.hasText || title.hasText ? PaddingTwo : 0
}
public override static func estimatedHeight(forRow json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
return 197
}
//------------------------------------------------------
// MARK: - Methods
//------------------------------------------------------
private func setDefaultState() {
title.font = MFStyler.fontH3()
message.font = MFStyler.fontB3()
button.setAsSecondaryCustom()
button.isHidden = false
imageLoader.imageView.contentMode = .scaleAspectFit
imageLoader.addSizeConstraintsForAspectRatio = true
bottomTitlePadding = PaddingOne
}
override open func reset() {
super.reset()
title.reset()
message.reset()
button.reset()
imageLeadingConstraint?.constant = 16
imageLoader.reset()
setDefaultState()
}
open override func setAsMolecule() {
super.setAsMolecule()
title.setAsMolecule()
message.setAsMolecule()
button.setAsMolecule()
imageLoader.setAsMolecule()
setDefaultState()
}
open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
guard let dictionary = json else { return }
if let padding = dictionary.optionalCGFloatForKey("bottomTitlePadding") {
bottomTitlePadding = padding
}
title.setWithJSON(dictionary.optionalDictionaryForKey("title"), delegateObject: delegateObject, additionalData: additionalData)
message.setWithJSON(dictionary.optionalDictionaryForKey("message"), delegateObject: delegateObject, additionalData: additionalData)
imageLoader.setWithJSON(dictionary.optionalDictionaryForKey("image"), delegateObject: delegateObject, additionalData: additionalData)
if let buttonDictionary = dictionary.optionalDictionaryForKey("button") {
button.setWithJSON(buttonDictionary, delegateObject: delegateObject, additionalData: additionalData)
} else {
button.isHidden = true
}
}
}

View File

@ -62,7 +62,7 @@ open class Carousel: ViewConstrainingView {
pinView(toSuperView: collectionView)
collectionViewHeight = collectionView.heightAnchor.constraint(equalToConstant: 300)
collectionViewHeight?.isActive = true
collectionViewHeight?.isActive = false
}
open override func updateView(_ size: CGFloat) {
@ -81,12 +81,19 @@ open class Carousel: ViewConstrainingView {
// MARK: - MVMCoreUIMoleculeViewProtocol
open override func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) {
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
collectionView.backgroundColor = backgroundColor
collectionView.layer.borderColor = backgroundColor?.cgColor
collectionView.layer.borderWidth = (json?.boolForKey("border") ?? false) ? 1 : 0
backgroundColor = .white
registerCells(with: json, delegateObject: delegateObject)
setupLayout(with: json)
prepareMolecules(with: json)
itemWidthPercent = (json?.optionalCGFloatForKey("itemWidthPercent") ?? 100) / 100
setAlignment(with: json?.optionalStringForKey("itemAlignment"))
collectionViewHeight?.constant = json?.optionalCGFloatForKey("height") ?? 300
if let height = json?.optionalCGFloatForKey("height") {
collectionViewHeight?.constant = height
collectionViewHeight?.isActive = true
}
setupPagingMolecule(json: json?.optionalDictionaryForKey("pagingMolecule"), delegateObject: delegateObject)
collectionView.reloadData()
}
@ -248,6 +255,10 @@ extension Carousel: UICollectionViewDelegateFlowLayout {
let itemWidth = collectionView.bounds.width * itemWidthPercent
return CGSize(width: itemWidth, height: collectionView.bounds.height)
}
public func collectionView(_ collectionView: UICollectionView, didEndDisplaying cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
(cell as? MoleculeCollectionViewCell)?.setPeaking(false, animated: false)
}
}
extension Carousel: UICollectionViewDataSource {

View File

@ -0,0 +1,180 @@
//
// ProgressBarView.swift
// MVMCoreUI
//
// Created by Panth Patel on 5/3/19.
// Copyright © 2019 Verizon Wireless. All rights reserved.
//
import UIKit
@objcMembers public class CornerLabels: ViewConstrainingView {
let topLeftLabel = Label.commonLabelB1(true)
let topRightLabel = Label.commonLabelB1(true)
let bottomLeftLabel = Label.commonLabelB3(true)
let bottomRightLabel = Label.commonLabelB3(true)
let topLabelsView = MVMCoreUICommonViewsUtility.commonView()
let bottomLabelsView = MVMCoreUICommonViewsUtility.commonView()
/// The space between the molecule and top labels. Set to 0 if the top labels or molecule are not set.
var spaceAboveMolecule: CGFloat = 6.0 {
didSet {
if spaceAboveMolecule != oldValue {
topLabelToMoleculeConstraint?.constant = spaceAboveMolecule
}
}
}
/// The space between the molecule and bottom labels. Set to 0 if the bottom labels or molecule are not set.
var spaceBelowMolecule: CGFloat = 6.0 {
didSet {
if spaceBelowMolecule != oldValue {
bottomLabelToMoleculeConstraint?.constant = spaceBelowMolecule
}
}
}
var topLabelToMoleculeConstraint: NSLayoutConstraint?
var bottomLabelToMoleculeConstraint: NSLayoutConstraint?
public override func addMolecule(_ molecule: UIView) {
insertSubview(molecule, at: 0)
topLabelToMoleculeConstraint?.isActive = false
bottomLabelToMoleculeConstraint?.isActive = false
molecule.leftAnchor.constraint(equalTo: layoutMarginsGuide.leftAnchor).isActive = true
layoutMarginsGuide.rightAnchor.constraint(equalTo: molecule.rightAnchor).isActive = true
topLabelToMoleculeConstraint = molecule.topAnchor.constraint(equalTo: topLabelsView.bottomAnchor, constant: spaceAboveMolecule)
topLabelToMoleculeConstraint?.isActive = true
bottomLabelToMoleculeConstraint = bottomLabelsView.topAnchor.constraint(equalTo: molecule.bottomAnchor, constant: spaceBelowMolecule)
bottomLabelToMoleculeConstraint?.isActive = true
}
// MARK: - MVMCoreViewProtocol
open override func updateView(_ size: CGFloat) {
super.updateView(size)
topLeftLabel.updateView(size)
topRightLabel.updateView(size)
bottomLeftLabel.updateView(size)
bottomRightLabel.updateView(size)
}
public override func setupView() {
super.setupView()
shouldSetupMoleculeFromJSON = true
guard topLeftLabel.superview == nil else {
return
}
topRightLabel.textAlignment = .right
bottomRightLabel.textAlignment = .right
addSubview(topLabelsView)
addSubview(bottomLabelsView)
topLabelsView.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor).isActive = true
topLabelsView.leftAnchor.constraint(equalTo: layoutMarginsGuide.leftAnchor).isActive = true
layoutMarginsGuide.rightAnchor.constraint(equalTo: topLabelsView.rightAnchor).isActive = true
topLabelToMoleculeConstraint = bottomLabelsView.topAnchor.constraint(equalTo: topLabelsView.bottomAnchor, constant: 0)
topLabelToMoleculeConstraint?.isActive = true
bottomLabelToMoleculeConstraint = topLabelToMoleculeConstraint
bottomLabelsView.leftAnchor.constraint(equalTo: layoutMarginsGuide.leftAnchor).isActive = true
layoutMarginsGuide.rightAnchor.constraint(equalTo: bottomLabelsView.rightAnchor).isActive = true
layoutMarginsGuide.bottomAnchor.constraint(equalTo: bottomLabelsView.bottomAnchor).isActive = true
topLabelsView.addSubview(topLeftLabel)
topLabelsView.addSubview(topRightLabel)
setCompetitionConstraints(topLeftLabel,topRightLabel)
bottomLabelsView.addSubview(bottomLeftLabel)
bottomLabelsView.addSubview(bottomRightLabel)
setCompetitionConstraints(bottomLeftLabel,bottomRightLabel)
topLeftLabel.topAnchor.constraint(equalTo: topLabelsView.topAnchor).isActive = true
topLeftLabel.leftAnchor.constraint(equalTo: topLabelsView.leftAnchor).isActive = true
topLabelsView.bottomAnchor.constraint(greaterThanOrEqualTo: topLeftLabel.bottomAnchor).isActive = true
topRightLabel.topAnchor.constraint(equalTo: topLabelsView.topAnchor).isActive = true
topLabelsView.rightAnchor.constraint(equalTo: topRightLabel.rightAnchor).isActive = true
topLabelsView.bottomAnchor.constraint(greaterThanOrEqualTo: topRightLabel.bottomAnchor).isActive = true
var constraint = topLabelsView.bottomAnchor.constraint(equalTo: topLeftLabel.bottomAnchor)
constraint.priority = topLeftLabel.contentHuggingPriority(for: .vertical) - 10
constraint.isActive = true
constraint = topLabelsView.bottomAnchor.constraint(equalTo: topRightLabel.bottomAnchor)
constraint.priority = topRightLabel.contentHuggingPriority(for: .vertical) - 10
constraint.isActive = true
topRightLabel.leftAnchor.constraint(equalTo: topLeftLabel.rightAnchor, constant: 16).isActive = true
bottomLeftLabel.topAnchor.constraint(equalTo: bottomLabelsView.topAnchor).isActive = true
bottomLeftLabel.leftAnchor.constraint(equalTo: bottomLabelsView.leftAnchor).isActive = true
bottomLabelsView.bottomAnchor.constraint(greaterThanOrEqualTo: bottomLeftLabel.bottomAnchor).isActive = true
bottomRightLabel.topAnchor.constraint(equalTo: bottomLabelsView.topAnchor).isActive = true
bottomRightLabel.rightAnchor.constraint(equalTo: bottomLabelsView.rightAnchor).isActive = true
bottomLabelsView.bottomAnchor.constraint(greaterThanOrEqualTo: bottomRightLabel.bottomAnchor).isActive = true
constraint = bottomLabelsView.bottomAnchor.constraint(equalTo: bottomLeftLabel.bottomAnchor)
constraint.priority = bottomLeftLabel.contentHuggingPriority(for: .vertical) - 10
constraint.isActive = true
constraint = bottomLabelsView.bottomAnchor.constraint(equalTo: bottomRightLabel.bottomAnchor)
constraint.priority = bottomRightLabel.contentHuggingPriority(for: .vertical) - 10
constraint.isActive = true
bottomRightLabel.leftAnchor.constraint(greaterThanOrEqualTo: bottomLeftLabel.rightAnchor, constant: 16).isActive = true
}
/// Sets the rules for the labels if they were to collide. The first view will take priority, but the second view has a minimum width when competing.
func setCompetitionConstraints(_ view1: UIView,_ view2: UIView) {
view1.setContentHuggingPriority(UILayoutPriority(rawValue: 700), for: .horizontal)
view2.setContentHuggingPriority(UILayoutPriority(rawValue: 750), for: .horizontal)
view1.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 350), for: .horizontal)
view2.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 300), for: .horizontal)
let width = view2.widthAnchor.constraint(equalTo: self.widthAnchor, multiplier: 0.40)
width.priority = UILayoutPriority(rawValue: 400)
width.isActive = true
}
// MARK: - MVMCoreUIMoleculeViewProtocol
open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
topLeftLabel.setWithJSON(json?.optionalDictionaryForKey("topLeftLabel"), delegateObject: delegateObject, additionalData: additionalData)
topRightLabel.setWithJSON(json?.optionalDictionaryForKey("topRightLabel"), delegateObject: delegateObject, additionalData: additionalData)
bottomLeftLabel.setWithJSON(json?.optionalDictionaryForKey("bottomLeftLabel"), delegateObject: delegateObject, additionalData: additionalData)
bottomRightLabel.setWithJSON(json?.optionalDictionaryForKey("bottomRightLabel"), delegateObject: delegateObject, additionalData: additionalData)
topLabelToMoleculeConstraint?.constant = (molecule != nil && (topLeftLabel.hasText || topRightLabel.hasText)) ? spaceAboveMolecule : 0
bottomLabelToMoleculeConstraint?.constant = (molecule != nil && (bottomLeftLabel.hasText || bottomRightLabel.hasText)) ? spaceBelowMolecule : 0
}
public override func setAsMolecule() {
super.setAsMolecule()
styleDefault()
}
public override func reset() {
super.reset()
styleDefault()
spaceAboveMolecule = 6.0
spaceBelowMolecule = 6.0
molecule?.reset?()
}
func styleDefault() {
topLeftLabel.styleB1(true)
topRightLabel.styleB1(true)
bottomLeftLabel.styleB3(true)
bottomRightLabel.styleB3(true)
}
public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
return 34
}
}

View File

@ -11,6 +11,7 @@ import UIKit
open class HeadlineBody: ViewConstrainingView {
let headlineLabel = Label.commonLabelH2(true)
let messageLabel = Label.commonLabelB2(true)
var spaceBetweenLabelsConstant = PaddingTwo
var spaceBetweenLabels: NSLayoutConstraint?
var leftConstraintTitle: NSLayoutConstraint?
var rightConstraintTitle: NSLayoutConstraint?
@ -44,7 +45,7 @@ open class HeadlineBody: ViewConstrainingView {
topPin = headlineLabel.topAnchor.constraint(equalTo: topAnchor, constant: 0)
topPin?.isActive = true
spaceBetweenLabels = messageLabel.topAnchor.constraint(equalTo: headlineLabel.bottomAnchor, constant: PaddingTwo)
spaceBetweenLabels = messageLabel.topAnchor.constraint(equalTo: headlineLabel.bottomAnchor, constant: spaceBetweenLabelsConstant)
spaceBetweenLabels?.isActive = true
leftConstraintTitle = headlineLabel.leftAnchor.constraint(equalTo: leftAnchor)
@ -66,7 +67,7 @@ open class HeadlineBody: ViewConstrainingView {
// MARK: - Constraining
public func setSpacing() {
if headlineLabel.hasText && messageLabel.hasText {
spaceBetweenLabels?.constant = PaddingTwo
spaceBetweenLabels?.constant = spaceBetweenLabelsConstant
} else {
spaceBetweenLabels?.constant = 0
}
@ -96,6 +97,7 @@ open class HeadlineBody: ViewConstrainingView {
super.reset()
headlineLabel.styleH2(true)
messageLabel.styleB2(true)
spaceBetweenLabelsConstant = PaddingTwo
}
public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {

View File

@ -0,0 +1,85 @@
//
// ImageHeadlineBody.swift
// MVMCoreUI
//
// Created by Scott Pfeil on 8/1/19.
// Copyright © 2019 Verizon Wireless. All rights reserved.
//
import UIKit
@objcMembers open class ImageHeadlineBody: ViewConstrainingView {
let headlineBody = HeadlineBody(frame: .zero)
let imageView = MFLoadImageView()
var constraintBetweenImageLabelsConstant: CGFloat = 16
var constraintBetweenImageLabels: NSLayoutConstraint?
// MARK: - MFViewProtocol
open override func setupView() {
guard subviews.count == 0 else {
return
}
MVMCoreUIUtility.setMarginsFor(self, leading: 0, top: 0, trailing: 0, bottom: 0)
headlineBody.headlineLabel.styleB1(true)
headlineBody.spaceBetweenLabelsConstant = 0
addSubview(headlineBody)
addSubview(imageView)
NSLayoutConstraint.pinViewTop(toSuperview: headlineBody, useMargins: true, constant: 0).isActive = true
NSLayoutConstraint.pinViewRight(toSuperview: headlineBody, useMargins: true, constant: 0).isActive = true
layoutMarginsGuide.bottomAnchor.constraint(greaterThanOrEqualTo: headlineBody.bottomAnchor).isActive = true
var constraint = NSLayoutConstraint.pinViewBottom(toSuperview: headlineBody, useMargins: true, constant: 0)
constraint.priority = .defaultLow
constraint.isActive = true
imageView.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
NSLayoutConstraint.pinViewLeft(toSuperview: imageView, useMargins: true, constant: 0).isActive = true
imageView.topAnchor.constraint(greaterThanOrEqualTo: layoutMarginsGuide.topAnchor).isActive = true
layoutMarginsGuide.bottomAnchor.constraint(greaterThanOrEqualTo: imageView.bottomAnchor).isActive = true
constraint = NSLayoutConstraint.pinViewBottom(toSuperview: imageView, useMargins: true, constant: 0)
constraint.priority = UILayoutPriority(rawValue: 200)
constraint.isActive = true
constraint = NSLayoutConstraint.pinViewTop(toSuperview: imageView, useMargins: true, constant: 0)
constraint.priority = UILayoutPriority(rawValue: 200)
constraint.isActive = true
constraintBetweenImageLabels = headlineBody.leadingAnchor.constraint(equalTo: imageView.trailingAnchor, constant: constraintBetweenImageLabelsConstant)
constraintBetweenImageLabels?.isActive = true
}
open override func updateView(_ size: CGFloat) {
super.updateView(size)
headlineBody.updateView(size)
imageView.updateView(size)
}
// MARK: - MVMCoreUIMoleculeViewProtocol
open override func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) {
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
headlineBody.setWithJSON(json?.optionalDictionaryForKey("headlineBody"), delegateObject: delegateObject, additionalData: additionalData)
let imageJSON = json?.optionalDictionaryForKey("image")
imageView.setWithJSON(imageJSON, delegateObject: delegateObject, additionalData: additionalData)
constraintBetweenImageLabels?.constant = imageJSON != nil ? constraintBetweenImageLabelsConstant : 0
}
open override func setAsMolecule() {
super.setAsMolecule()
headlineBody.setAsMolecule()
imageView.setAsMolecule()
}
open override func reset() {
super.reset()
headlineBody.reset()
headlineBody.headlineLabel.styleB1(true)
headlineBody.spaceBetweenLabelsConstant = 0
imageView.reset()
}
public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
return 95
}
}

View File

@ -297,7 +297,9 @@ static CGFloat const IndicatorRectangleHeight = 4;
if (selectedIndex != NSNotFound) {
self.currentPage = selectedIndex;
[self sendActionsForControlEvents:UIControlEventValueChanged];
self.pagingTouchBlock(self);
if (self.pagingTouchBlock) {
self.pagingTouchBlock(self);
}
}
}
}
@ -351,7 +353,9 @@ static CGFloat const IndicatorRectangleHeight = 4;
if ((index < self.numberOfPages && index >= 0) || self.alwaysSendingControlEvent) {
[self setCurrentPage:index animated:NO];
[self sendActionsForControlEvents:UIControlEventValueChanged];
self.pagingTouchBlock(self);
if (self.pagingTouchBlock) {
self.pagingTouchBlock(self);
}
}
}

View File

@ -37,6 +37,11 @@ open class MoleculeCollectionViewCell: UICollectionViewCell, MVMCoreUIMoleculeVi
}
isAccessibilityElement = false
contentView.isAccessibilityElement = false
if #available(iOS 11.0, *) {
insetsLayoutMarginsFromSafeArea = false
contentView.insetsLayoutMarginsFromSafeArea = false
contentView.preservesSuperviewLayoutMargins = false
}
// Covers the card when peaking.
peakingCover.backgroundColor = .white

View File

@ -80,6 +80,11 @@ import UIKit
public func setupView() {
selectionStyle = .none
if #available(iOS 11.0, *) {
insetsLayoutMarginsFromSafeArea = false
contentView.insetsLayoutMarginsFromSafeArea = false
contentView.preservesSuperviewLayoutMargins = false
}
}
// MARK: - MVMCoreUIMoleculeViewProtocol
@ -98,7 +103,7 @@ import UIKit
}
// Add the caret if there is an action and it's not declared hidden.
if let _ = json?.optionalDictionaryForKey("actionMap"), json!.boolForKey("hideArrow") {
if let _ = json?.optionalDictionaryForKey("actionMap"), !json!.boolForKey("hideArrow") {
addCaretViewAccessory()
} else {
accessoryView = nil
@ -118,11 +123,6 @@ import UIKit
contentView.addSubview(moleculeView)
let standardConstraints = (moleculeView as? MVMCoreUIViewConstrainingProtocol)?.useStandardConstraints?() ?? true
NSLayoutConstraint.activate(Array(NSLayoutConstraint.pinView(toSuperview: moleculeView, useMargins: standardConstraints).values))
if standardConstraints {
let constraint = contentView.heightAnchor.constraint(equalToConstant: 80)
constraint.priority = .defaultLow
constraint.isActive = true
}
molecule = moleculeView
}
} else {
@ -147,7 +147,7 @@ import UIKit
guard let moleculeJSON = json?.optionalDictionaryForKey(KeyMolecule), let height = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: moleculeJSON)?.estimatedHeight?(forRow: moleculeJSON, delegateObject: delegateObject) else {
return 80
}
return max(80, height)
return max(2 * PaddingDefaultVerticalSpacing3, height)
}
public static func name(forReuse molecule: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> String? {

View File

@ -8,41 +8,73 @@
import Foundation
public class ProgressBar: UIProgressView {
var isRounded = Bool()
var thickness : Float = 0.0 {
@objcMembers open class ProgressBar: UIProgressView, MVMCoreUIMoleculeViewProtocol, MVMCoreViewProtocol {
var isRounded = false
var thickness: CGFloat = 8.0 {
willSet(newValue) {
heightAnchor.constraint(equalToConstant: CGFloat(newValue)).isActive = true
switch isRounded {
case true:
layer.cornerRadius = CGFloat(newValue/2)
clipsToBounds = true
default:
heightAnchor.constraint(equalToConstant: newValue).isActive = true
if isRounded {
layer.cornerRadius = newValue/2.0
} else {
progressViewStyle = .bar
}
}
}
public override init(frame: CGRect) {
super.init(frame: frame)
setupView()
}
public required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupView()
}
init() {
super.init(frame: .zero)
setupView()
}
// MARK: - MVMCoreViewProtocol
public func setupView() {
clipsToBounds = true
translatesAutoresizingMaskIntoConstraints = false
reset()
}
public func updateView(_ size: CGFloat) {
}
// MARK: - MVMCoreUIMoleculeViewProtocol
public func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) {
isRounded = json?.optionalBoolForKey("roundedRect") ?? false
thickness = json?.floatFromStringForKey("thickness") ?? Float(0.0)
let percentage = json?.floatFromStringForKey("percent")
progress = (percentage ?? Float(0.0))/100
progressTintColor = UIColor.mfBattleshipGrey()
trackTintColor = UIColor.mfLighterGray()
if let progresscolor = json?.optionalStringForKey("progressColor") {
if !progresscolor.isEmpty {
progressTintColor = UIColor.mfGet(forHex: progresscolor)
}
if let isRounded = json?.optionalBoolForKey("roundedRect") {
self.isRounded = isRounded
}
if let backgroundcolor = json?.optionalStringForKey("backgroundColor") {
if !backgroundcolor.isEmpty {
trackTintColor = UIColor.mfGet(forHex: backgroundcolor)
}
if let thickness = json?.optionalCGFloatForKey("thickness") {
self.thickness = thickness
}
if let percentage = json?["percent"] as? Float {
progress = percentage/100.0
}
if let progressColor = json?.optionalStringForKey("progressColor") {
progressTintColor = UIColor.mfGet(forHex: progressColor)
}
if let backgroundColor = json?.optionalStringForKey("backgroundColor") {
trackTintColor = UIColor.mfGet(forHex: backgroundColor)
}
}
public func reset() {
isRounded = false
thickness = 8
progress = 0
progressTintColor = UIColor.mfCerulean()
trackTintColor = UIColor.mfSilver()
}
public static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
return 8
}
}

View File

@ -1,100 +0,0 @@
//
// ProgressBarView.swift
// MVMCoreUI
//
// Created by Panth Patel on 5/3/19.
// Copyright © 2019 Verizon Wireless. All rights reserved.
//
import UIKit
@objcMembers public class ProgressBarWithLabel: ViewConstrainingView {
var progress = ProgressBar()
var topleftlabel = Label()
var toprightlabel = Label()
var bottomleftlabel = Label()
var bottomrightlabel = Label()
open override func needsToBeConstrained() -> Bool {
return true
}
open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
let progressbarjson = json?.optionalDictionaryForKey("progressbar")
progress.setWithJSON(progressbarjson, delegateObject: delegateObject, additionalData: additionalData)
let topleftlabeljson = json?.optionalDictionaryForKey("label")
let toprightlabeljson = json?.optionalDictionaryForKey("toprightlabel")
let bottomleftlabeljson = json?.optionalDictionaryForKey("bottomleftlabel")
let bottomrightlabeljson = json?.optionalDictionaryForKey("bottomrightlabel")
topleftlabel.setWithJSON(topleftlabeljson, delegateObject: delegateObject, additionalData: additionalData)
toprightlabel.setWithJSON(toprightlabeljson, delegateObject: delegateObject, additionalData: additionalData)
bottomleftlabel.setWithJSON(bottomleftlabeljson, delegateObject: delegateObject, additionalData: additionalData)
bottomrightlabel.setWithJSON(bottomrightlabeljson, delegateObject: delegateObject, additionalData: additionalData)
}
override open func setupView() {
super.setupView()
addSubview(topleftlabel)
addSubview(toprightlabel)
addSubview(bottomleftlabel)
addSubview(bottomrightlabel)
addSubview(progress)
progress.translatesAutoresizingMaskIntoConstraints = false
topleftlabel.leftAnchor.constraint(equalTo: self.leftAnchor).isActive = true
topleftlabel.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
let topleftwidthconstraint = NSLayoutConstraint(item: topleftlabel, attribute: .width, relatedBy: .equal, toItem: self, attribute: .width, multiplier: 0.5, constant: 0.0)
topleftwidthconstraint.priority = UILayoutPriority(100)
topleftwidthconstraint.isActive = true
topleftlabel.setContentHuggingPriority(UILayoutPriority(801), for: .horizontal)
topleftlabel.setContentHuggingPriority(UILayoutPriority(801), for: .vertical)
NSLayoutConstraint(item: toprightlabel, attribute: .leading, relatedBy: .equal, toItem: topleftlabel, attribute: .trailing, multiplier: 1.0, constant: PaddingTwo).isActive = true
toprightlabel.rightAnchor.constraint(equalTo: self.rightAnchor).isActive = true
toprightlabel.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
toprightlabel.textAlignment = .right
toprightlabel.setContentHuggingPriority(UILayoutPriority(802), for: .horizontal)
toprightlabel.setContentHuggingPriority(UILayoutPriority(802), for: .vertical)
var topconstraint = progress.topAnchor.constraint(equalTo: topleftlabel.bottomAnchor, constant: PaddingTwo)
topconstraint.priority = UILayoutPriority(249)
topconstraint.isActive = true
progress.topAnchor.constraint(greaterThanOrEqualTo: topleftlabel.bottomAnchor, constant: PaddingTwo).isActive = true
topconstraint = progress.topAnchor.constraint(equalTo: toprightlabel.bottomAnchor, constant: PaddingTwo)
topconstraint.priority = UILayoutPriority(249)
topconstraint.isActive = true
progress.topAnchor.constraint(greaterThanOrEqualTo: toprightlabel.bottomAnchor, constant: PaddingTwo).isActive = true
progress.leftAnchor.constraint(equalTo: self.leftAnchor).isActive = true
progress.rightAnchor.constraint(equalTo: self.rightAnchor).isActive = true
bottomleftlabel.topAnchor.constraint(equalTo: progress.bottomAnchor, constant: PaddingTwo).isActive = true
bottomleftlabel.leftAnchor.constraint(equalTo: self.leftAnchor).isActive = true
let bottomleftwidthconstraint = NSLayoutConstraint(item: bottomleftlabel, attribute: .width, relatedBy: .equal, toItem: self, attribute: .width, multiplier: 0.5, constant: 0.0)
bottomleftwidthconstraint.priority = UILayoutPriority(100)
bottomleftwidthconstraint.isActive = true
bottomleftlabel.setContentHuggingPriority(UILayoutPriority(801), for: .horizontal)
bottomleftlabel.setContentHuggingPriority(UILayoutPriority(801), for: .vertical)
NSLayoutConstraint(item: bottomrightlabel, attribute: .leading, relatedBy: .equal, toItem: bottomleftlabel, attribute: .trailing, multiplier: 1.0, constant: PaddingTwo).isActive = true
bottomrightlabel.topAnchor.constraint(equalTo: progress.bottomAnchor, constant: PaddingTwo).isActive = true
bottomrightlabel.rightAnchor.constraint(equalTo: self.rightAnchor).isActive = true
bottomrightlabel.textAlignment = .right
bottomrightlabel.setContentHuggingPriority(UILayoutPriority(802), for: .horizontal)
bottomrightlabel.setContentHuggingPriority(UILayoutPriority(802), for: .vertical)
var bottomconstraint = bottomAnchor.constraint(equalTo: bottomleftlabel.bottomAnchor, constant: PaddingTwo)
bottomconstraint.priority = UILayoutPriority(249)
bottomconstraint.isActive = true
bottomAnchor.constraint(greaterThanOrEqualTo: bottomleftlabel.bottomAnchor, constant: PaddingTwo).isActive = true
bottomconstraint = bottomAnchor.constraint(equalTo: bottomrightlabel.bottomAnchor, constant: PaddingTwo)
bottomconstraint.priority = UILayoutPriority(249)
bottomconstraint.isActive = true
bottomAnchor.constraint(greaterThanOrEqualTo: bottomrightlabel.bottomAnchor, constant: PaddingTwo).isActive = true
}
}

View File

@ -0,0 +1,44 @@
//
// Scroller.swift
// MVMCoreUI
//
// Created by Scott Pfeil on 7/23/19.
// Copyright © 2019 Verizon Wireless. All rights reserved.
//
import UIKit
@objcMembers open class Scroller: ViewConstrainingView {
public let scrollView = UIScrollView(frame: .zero)
public let contentView = MVMCoreUICommonViewsUtility.commonView()
override open func setupView() {
super.setupView()
guard scrollView.superview == nil else {
return
}
translatesAutoresizingMaskIntoConstraints = false
scrollView.translatesAutoresizingMaskIntoConstraints = false
addConstrainedView(scrollView)
scrollView.addSubview(contentView)
NSLayoutConstraint.constraintPinSubview(toSuperview: contentView)
let constraint = contentView.widthAnchor.constraint(equalTo: scrollView.widthAnchor, multiplier: 1.0)
constraint.priority = UILayoutPriority(rawValue: 999)
constraint.isActive = true
}
open override func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) {
guard let json = json, let moleculeJSON = json.optionalDictionaryForKey(KeyMolecule) else {
return
}
if molecule == nil {
if let moleculeView = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject, constrainIfNeeded: true) {
contentView.addSubview(moleculeView)
pinView(toSuperView: moleculeView)
molecule = moleculeView
}
} else {
molecule?.setWithJSON(moleculeJSON, delegateObject: delegateObject, additionalData: additionalData)
}
}
}

View File

@ -15,11 +15,6 @@ public class StandardHeaderView: ViewConstrainingView {
open override func updateView(_ size: CGFloat) {
super.updateView(size)
separatorView?.updateView(size)
if separatorView?.isHidden ?? true {
let margins = MVMCoreUIUtility.getMarginsFor(self)
MVMCoreUIUtility.setMarginsFor(self, leading: margins.left, top: margins.top, trailing: margins.right, bottom: 0)
bottomPin?.constant = 0
}
}
public override func setupView() {

View File

@ -39,7 +39,7 @@
@"textField" : MFTextField.class,
@"digitTextField" : MFDigitTextField.class,
@"checkbox" : MVMCoreUICheckBox.class,
@"progressBarWithLabel" : ProgressBarWithLabel.class,
@"cornerLabels" : CornerLabels.class,
@"progressBar": ProgressBar.class,
@"textField": MFTextField.class,
@"checkbox": MVMCoreUICheckBox.class,
@ -47,13 +47,16 @@
@"listItem": MoleculeTableViewCell.class,
@"switchLineItem": SwitchLineItem.class,
@"switch": Switch.class,
@"image": MFLoadImageView.class,
@"leftRightLabelView": LeftRightLabelView.class,
@"actionDetailWithImage": ActionDetailWithImage.class,
@"image": MFLoadImageView.class,
@"moduleMolecule": ModuleMolecule.class,
@"headlineBody": HeadlineBody.class,
@"carousel": Carousel.class,
@"carouselItem": MoleculeCollectionViewCell.class,
@"barsPager": MVMCoreUIPageControl.class,
@"scroller": Scroller.class,
@"imageHeadlineBody": ImageHeadlineBody.class
} mutableCopy];
});
return mapping;

View File

@ -22,7 +22,9 @@
@"textFieldListForm" : [[MVMCoreViewControllerProgrammaticMappingObject alloc] initWithClass:[TextFieldListFormViewController class]],
@"moleculeStack" : [[MVMCoreViewControllerProgrammaticMappingObject alloc] initWithClass:[MoleculeStackTemplate class]],
@"centerMoleculeStack" : [[MVMCoreViewControllerProgrammaticMappingObject alloc] initWithClass:[MoleculeStackCenteredTemplate class]],
@"moleculeList" : [[MVMCoreViewControllerProgrammaticMappingObject alloc] initWithClass:[MoleculeListTemplate class]]
@"moleculeList" : [[MVMCoreViewControllerProgrammaticMappingObject alloc] initWithClass:[MoleculeListTemplate class]],
@"threeLayer" :
[[MVMCoreViewControllerProgrammaticMappingObject alloc] initWithClass:[ThreeLayerTemplate class]]
} mutableCopy];
});
return viewControllerMapping;

View File

@ -12,4 +12,8 @@
/// returns a module for the corresponding module name.
- (nullable NSDictionary *)getModuleWithName:(nullable NSString *)name;
@optional
/// Notifies the delegate that the molecule layout update. Should be called when the layout may change due to an async method.
- (void)moleculeLayoutUpdated:(nonnull UIView <MVMCoreUIMoleculeViewProtocol>*)molecule;
@end

View File

@ -29,6 +29,7 @@ typedef NS_ENUM(NSUInteger, MFTimeFormatUnit) {
extern CGFloat const PaddingDefault;
extern CGFloat const PaddingDefaultHorizontalSpacing;
extern CGFloat const PaddingDefaultVerticalSpacing;
extern CGFloat const PaddingDefaultVerticalSpacing3;
extern CGFloat const PaddingBetweenFields;
extern CGFloat const PaddingHorizontalHeadlineWhiteView;
extern CGFloat const PaddingHorizontalLarge;

View File

@ -18,6 +18,7 @@
CGFloat const PaddingDefault = 24;
CGFloat const PaddingDefaultHorizontalSpacing = 32;
CGFloat const PaddingDefaultVerticalSpacing = 32;
CGFloat const PaddingDefaultVerticalSpacing3 = 24;
CGFloat const PaddingBetweenFields = 24;
CGFloat const PaddingHorizontalHeadlineWhiteView = 60;
CGFloat const PaddingHorizontalLarge = 72;
@ -98,7 +99,7 @@ CGFloat const LabelWithInternalButtonLineSpace = 2;
+ (void)setDefaultMarginsForView:(nullable UIView *)view size:(CGFloat)size horizontal:(BOOL)horizontal vertical:(BOOL)vertical {
[MVMCoreDispatchUtility performBlockOnMainThread:^{
CGFloat horizontalPadding = horizontal ? [MFStyler defaultHorizontalPaddingForSize:size] : 0;
CGFloat verticalPadding = vertical ? PaddingDefaultVerticalSpacing : 0;
CGFloat verticalPadding = vertical ? PaddingDefaultVerticalSpacing3 : 0;
[MVMCoreUIUtility setMarginsForView:view leading:horizontalPadding top:verticalPadding trailing:horizontalPadding bottom:verticalPadding];
}];
}

View File

@ -0,0 +1,23 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "closeXBlack.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "closeXBlack@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "closeXBlack@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 215 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 374 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 535 B

View File

@ -106,6 +106,17 @@ open class MoleculeListTemplate: ThreeLayerTableViewController {
return loadObject?.requestParameters?.modules
}
// MARK: - MoleculeDelegateProtocol
open override func moleculeLayoutUpdated(_ molecule: UIView & MVMCoreUIMoleculeViewProtocol) {
if let tableView = tableView {
let point = molecule.convert(molecule.bounds.origin, to: tableView)
if let indexPath = tableView.indexPathForRow(at: point), tableView.indexPathsForVisibleRows?.contains(indexPath) ?? false {
tableView.beginUpdates()
tableView.endUpdates()
}
}
}
// MARK: - Convenience
/// Returns the (identifier, class) of the molecule for the given map.
func getMoleculeInfo(with molecule: [AnyHashable: Any]?) -> (identifier: String, class: AnyClass, molecule: [AnyHashable: Any])? {

View File

@ -8,7 +8,7 @@
import UIKit
public class MoleculeStackTemplate: ThreeLayerViewController {
open class MoleculeStackTemplate: ThreeLayerViewController {
var observer: NSKeyValueObservation?
open override var loadObject: MVMCoreLoadObject? {
@ -25,18 +25,18 @@ self?.updateRequiredModules()
}
}
public override func spaceBetweenTopAndMiddle() -> CGFloat? {
open override func spaceBetweenTopAndMiddle() -> CGFloat? {
return 0
}
public override func viewForTop() -> UIView? {
open override func viewForTop() -> UIView? {
guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("header"), let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject() as? MVMCoreUIDelegateObject, constrainIfNeeded: true) else {
return nil
}
return molecule
}
public override func viewForMiddle() -> UIView? {
open override func viewForMiddle() -> UIView? {
guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("moleculeStack") else {
return nil
}
@ -46,7 +46,7 @@ stack.setWithJSON(moleculeJSON, delegateObject: delegateObject() as? MVMCoreUIDe
return stack
}
override public func viewForBottom() -> UIView? {
override open func viewForBottom() -> UIView? {
guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("footer"), let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject() as? MVMCoreUIDelegateObject, constrainIfNeeded: true) else {
return nil
}
@ -54,14 +54,14 @@ return molecule
}
// MARK: - cache handling
public override func pageTypesToListenFor() -> [Any]? {
open override func pageTypesToListenFor() -> [Any]? {
guard let pageType = self.pageType else {
return super.pageTypesToListenFor()
}
return [pageType]
}
public override func modulesToListenFor() -> [Any]? {
open override func modulesToListenFor() -> [Any]? {
return loadObject?.requestParameters?.modules
}

View File

@ -0,0 +1,52 @@
//
// ThreeLayerTemplate.swift
// MVMCoreUI
//
// Created by Scott Pfeil on 7/23/19.
// Copyright © 2019 Verizon Wireless. All rights reserved.
//
import UIKit
@objcMembers open class ThreeLayerTemplate: ThreeLayerViewController {
override open func viewDidLoad() {
super.viewDidLoad()
bottomViewOutsideOfScroll = true
// Do any additional setup after loading the view.
}
open override func newDataBuildScreen() {
super.newDataBuildScreen()
heightConstraint?.isActive = true
}
open override func viewForTop() -> UIView? {
guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("header"), let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject() as? MVMCoreUIDelegateObject, constrainIfNeeded: true) else {
return nil
}
return molecule
}
open override func viewForMiddle() -> UIView? {
guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("middle"), let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject() as? MVMCoreUIDelegateObject, constrainIfNeeded: true) else {
return nil
}
return molecule
}
override open func viewForBottom() -> UIView? {
guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("footer"), let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject() as? MVMCoreUIDelegateObject, constrainIfNeeded: true) else {
return nil
}
return molecule
}
open override func spaceBetweenMiddleAndBottom() -> CGFloat? {
return 0
}
open override func spaceBetweenTopAndMiddle() -> CGFloat? {
return 0
}
}

View File

@ -181,7 +181,7 @@ static const CGFloat VertialShadowOffset = 6;
+ (nonnull MFCustomButton *)addCloseButtonToView:(UIView *)view action:(ButtonTapBlock)actionBlock verticalCentered:(BOOL)verticalCentered {
MFCustomButton *button = [[MFCustomButton alloc] initWithFrame:CGRectZero];
button.translatesAutoresizingMaskIntoConstraints = NO;
[button setTitle:@"✕" forState:UIControlStateNormal];
[button setImage:[MVMCoreUIUtility imageNamed:@"closeXBlack"] forState:UIControlStateNormal];
button.titleLabel.font = [MFStyler fontForHeadlineAlternative];
//accessibility

View File

@ -71,8 +71,9 @@ NS_ASSUME_NONNULL_BEGIN
// Gets the constraint height to be whatever space is left in the scroll view.
+ (CGFloat)getVariableConstraintHeight:(CGFloat)currentConstant inScrollView:(nonnull UIScrollView *)scrollView minimumHeight:(CGFloat)minimumHeight;
// Sets the view's frame according to constraint.
/// Sets the view's frame according to constraints.
+ (void)sizeViewToFit:(nullable UIView *)view;
+ (void)sizeViewToFit:(UIView *)view forWidth:(nullable NSNumber *)width;
#pragma mark - Keyboard

View File

@ -119,7 +119,7 @@
#pragma mark - Sizing
+ (CGFloat)getWidth {
UIViewController *controller = [MVMCoreUISession sharedGlobal].splitViewController ?: [MVMCoreUISession sharedGlobal].navigationController ?: [UIApplication sharedApplication].keyWindow.rootViewController;
UIViewController *controller = [MVMCoreUISession sharedGlobal].splitViewController ?: [MVMCoreUISession sharedGlobal].navigationController;
if (controller) {
return CGRectGetWidth(controller.view.bounds);
} else {
@ -138,7 +138,7 @@
}
+ (CGFloat)getHeightOfView:(nonnull UIView *)view forWidth:(nullable NSNumber *)width {
CGFloat floatWidth = (width ? width.floatValue : CGRectGetWidth([MVMCoreNavigationHandler sharedNavigationHandler].navigationController.view.bounds));
CGFloat floatWidth = (width ? width.floatValue : [MVMCoreUIUtility getWidth]);
return [view systemLayoutSizeFittingSize:CGSizeMake(floatWidth, UILayoutFittingCompressedSize.height) withHorizontalFittingPriority:1000 verticalFittingPriority:250].height;
}
@ -192,6 +192,13 @@
view.frame = frame;
}
+ (void)sizeViewToFit:(UIView *)view forWidth:(nullable NSNumber *)width {
CGFloat height = [MVMCoreUIUtility getHeightOfView:view forWidth:width];
CGRect frame = view.frame;
frame.size.height = height;
view.frame = frame;
}
#pragma mark - Keyboard
+ (void)setScrollViewInsetForKeyboardShow:(nonnull NSNotification *)notification scrollView:(nonnull UIScrollView *)scrollView viewController:(nonnull UIViewController *)viewController rectToScrollTo:(nonnull CGRect (^)(void))rectToScrollTo {