Merge branch 'develop' into feature/carouselacc
This commit is contained in:
commit
791f2e98c7
@ -156,6 +156,9 @@
|
||||
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 */; };
|
||||
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 */; };
|
||||
D2E1FAE12268E81D00AEFD8C /* MoleculeListTemplate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2E1FAE02268E81D00AEFD8C /* MoleculeListTemplate.swift */; };
|
||||
DBC4391822442197001AB423 /* CaretView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBC4391622442196001AB423 /* CaretView.swift */; };
|
||||
DBC4391922442197001AB423 /* DashLine.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBC4391722442197001AB423 /* DashLine.swift */; };
|
||||
DBC4391B224421A0001AB423 /* CaretButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBC4391A224421A0001AB423 /* CaretButton.swift */; };
|
||||
@ -317,6 +320,9 @@
|
||||
D2C5001721F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MVMCoreUIViewControllerMappingObject.m; sourceTree = "<group>"; };
|
||||
D2E1FADA2260D3D200AEFD8C /* MVMCoreUIDelegateObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MVMCoreUIDelegateObject.swift; sourceTree = "<group>"; };
|
||||
DB891E822253FA8500022516 /* Label.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Label.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>"; };
|
||||
D2E1FAE02268E81D00AEFD8C /* MoleculeListTemplate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeListTemplate.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>"; };
|
||||
DBC4391A224421A0001AB423 /* CaretButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CaretButton.swift; sourceTree = "<group>"; };
|
||||
@ -405,6 +411,7 @@
|
||||
01DF566F21FA5AB300CC099B /* TextFieldListFormViewController.swift */,
|
||||
D2A5146022121FBF00345BFB /* MoleculeStackTemplate.swift */,
|
||||
D2A514622213643100345BFB /* MoleculeStackCenteredTemplate.swift */,
|
||||
D2E1FAE02268E81D00AEFD8C /* MoleculeListTemplate.swift */,
|
||||
);
|
||||
path = Templates;
|
||||
sourceTree = "<group>";
|
||||
@ -440,6 +447,7 @@
|
||||
D2A5145C2211D22A00345BFB /* MVMCoreUIMoleculeViewProtocol.h */,
|
||||
D2A5145E2211DDC100345BFB /* MoleculeStackView.swift */,
|
||||
D274CA322236A78900B01B62 /* StandardFooterView.swift */,
|
||||
D2E1FADC2268B25E00AEFD8C /* MoleculeTableViewCell.swift */,
|
||||
);
|
||||
path = Molecules;
|
||||
sourceTree = "<group>";
|
||||
@ -460,6 +468,7 @@
|
||||
D29DF2CC21E7C104003B2FB9 /* MFLoadingViewController.h */,
|
||||
D29DF2CD21E7C104003B2FB9 /* MFLoadingViewController.m */,
|
||||
D2A5146A2214905000345BFB /* ThreeLayerViewController.swift */,
|
||||
D2E1FADE2268B8E700AEFD8C /* ThreeLayerTableViewController.swift */,
|
||||
);
|
||||
path = BaseControllers;
|
||||
sourceTree = "<group>";
|
||||
@ -894,6 +903,7 @@
|
||||
D29DF2EF21ECEAE1003B2FB9 /* MFFonts.m in Sources */,
|
||||
D282AACB2243C61700C46919 /* ButtonView.swift in Sources */,
|
||||
0105618F224BBE7700E1557D /* FormValidator+FormParams.swift in Sources */,
|
||||
D2E1FADD2268B25E00AEFD8C /* MoleculeTableViewCell.swift in Sources */,
|
||||
D29DF2AE21E7B3A4003B2FB9 /* MFTextView.m in Sources */,
|
||||
D29DF18121E69E50003B2FB9 /* MFView.m in Sources */,
|
||||
D29DF18321E69E54003B2FB9 /* SeparatorView.m in Sources */,
|
||||
@ -909,6 +919,7 @@
|
||||
D29DF2C721E7BF57003B2FB9 /* MFTabBarInteractor.m in Sources */,
|
||||
D29DF29521E7ADB8003B2FB9 /* ProgrammaticScrollViewController.m in Sources */,
|
||||
D29DF16121E69996003B2FB9 /* MFViewController.m in Sources */,
|
||||
D2E1FAE12268E81D00AEFD8C /* MoleculeListTemplate.swift in Sources */,
|
||||
D22D1F47220496A30077CEC0 /* MVMCoreUISwitch.m in Sources */,
|
||||
D29DF28C21E7AC2B003B2FB9 /* ViewConstrainingView.m in Sources */,
|
||||
D29DF17B21E69E1F003B2FB9 /* PrimaryButton.m in Sources */,
|
||||
@ -916,6 +927,7 @@
|
||||
0198F79F225679880066C936 /* FormValidationProtocol.swift in Sources */,
|
||||
D29DF29821E7ADB8003B2FB9 /* MFScrollingViewController.m in Sources */,
|
||||
D29770C821F7C4AE00B2F0D0 /* TopLabelsView.m in Sources */,
|
||||
D2E1FADF2268B8E700AEFD8C /* ThreeLayerTableViewController.swift in Sources */,
|
||||
D20A9A5E2243D3E300ADE781 /* TwoButtonView.swift in Sources */,
|
||||
D29DF2AA21E7B2F9003B2FB9 /* MVMCoreUIConstants.m in Sources */,
|
||||
D2A5146122121FBF00345BFB /* MoleculeStackTemplate.swift in Sources */,
|
||||
|
||||
@ -127,4 +127,12 @@ open class CaretButton: MFCustomButton, MVMCoreUIMoleculeViewProtocol {
|
||||
disabledColor = UIColor.mfGet(forHex: disabledColorHex)
|
||||
}
|
||||
}
|
||||
|
||||
public func needsToBeConstrained() -> Bool {
|
||||
return true
|
||||
}
|
||||
|
||||
open func moleculeAlignment() -> UIStackView.Alignment {
|
||||
return UIStackView.Alignment.leading;
|
||||
}
|
||||
}
|
||||
|
||||
@ -141,4 +141,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)needsToBeConstrained {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (UIStackViewAlignment)moleculeAlignment {
|
||||
return UIStackViewAlignmentLeading;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@ -324,7 +324,7 @@
|
||||
}
|
||||
|
||||
// key used to send text value to server
|
||||
string = [map string:@"fieldKey"];
|
||||
string = [map string:KeyFieldKey];
|
||||
if (string.length > 0) {
|
||||
self.fieldKey = string;
|
||||
}
|
||||
|
||||
@ -13,9 +13,15 @@ open class CaretView: MFView {
|
||||
// MARK: - Properties
|
||||
//------------------------------------------------------
|
||||
|
||||
// Objc can't use float enum.
|
||||
@objc public static let thin: CGFloat = 6.0
|
||||
@objc public static let standard: CGFloat = 2.6
|
||||
@objc public static let thick: CGFloat = 1.5
|
||||
|
||||
private(set) var strokeColor: UIColor?
|
||||
private var lineWidth: CGFloat?
|
||||
|
||||
private var lineThickness: CGFloat?
|
||||
|
||||
//------------------------------------------------------
|
||||
// MARK: - Initialization
|
||||
//------------------------------------------------------
|
||||
@ -32,14 +38,19 @@ open class CaretView: MFView {
|
||||
super.init(coder: aDecoder)
|
||||
}
|
||||
|
||||
/// Can init with a specific line width.
|
||||
@objc public init(lineWidth: CGFloat) {
|
||||
super.init(frame: CGRect())
|
||||
|
||||
self.lineWidth = lineWidth
|
||||
}
|
||||
|
||||
/// Can init with a specific line thickness, scales based on width and height.
|
||||
@objc public init(lineThickness: CGFloat) {
|
||||
super.init(frame: CGRect())
|
||||
self.lineThickness = lineThickness
|
||||
}
|
||||
|
||||
@objc override open func setupView() {
|
||||
|
||||
defaultState()
|
||||
}
|
||||
|
||||
@ -48,7 +59,6 @@ open class CaretView: MFView {
|
||||
//------------------------------------------------------
|
||||
|
||||
private func defaultState() {
|
||||
|
||||
isOpaque = false
|
||||
isHidden = false
|
||||
backgroundColor = .clear
|
||||
@ -64,7 +74,7 @@ open class CaretView: MFView {
|
||||
let context = UIGraphicsGetCurrentContext()
|
||||
context?.clear(rect)
|
||||
|
||||
let lineWidthToDraw: CGFloat = lineWidth ?? frame.size.width / 2.6
|
||||
let lineWidthToDraw: CGFloat = lineWidth ?? frame.size.width / (lineThickness ?? 2.6)
|
||||
|
||||
let path = UIBezierPath()
|
||||
path.move(to: CGPoint(x: lineWidthToDraw / 2.0, y: 0.0))
|
||||
@ -80,7 +90,6 @@ open class CaretView: MFView {
|
||||
}
|
||||
|
||||
@objc public func setLineColor(_ color: UIColor?) {
|
||||
|
||||
strokeColor = color
|
||||
setNeedsDisplay()
|
||||
}
|
||||
@ -91,7 +100,6 @@ open class CaretView: MFView {
|
||||
|
||||
// Default values for view.
|
||||
@objc open override func setAsMolecule() {
|
||||
|
||||
defaultState()
|
||||
}
|
||||
|
||||
@ -120,4 +128,12 @@ open class CaretView: MFView {
|
||||
lineWidth = lineWidthValue
|
||||
}
|
||||
}
|
||||
|
||||
open override func needsToBeConstrained() -> Bool {
|
||||
return true
|
||||
}
|
||||
|
||||
open override func moleculeAlignment() -> UIStackView.Alignment {
|
||||
return UIStackView.Alignment.leading;
|
||||
}
|
||||
}
|
||||
|
||||
@ -268,7 +268,6 @@ import MVMCore
|
||||
}
|
||||
})
|
||||
attributedText = attributedString
|
||||
|
||||
} else if !MVMCoreGetterUtility.fequal(a: Float(standardFontSize), b: 0.0), let sizeObject: MFSizeObject = self.sizeObject ?? MFStyler.sizeObjectGeneric(forCurrentDevice: standardFontSize) {
|
||||
self.font = self.font.withSize(sizeObject.getValueBased(onSize: size))
|
||||
}
|
||||
@ -298,9 +297,12 @@ import MVMCore
|
||||
|
||||
@objc public func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: DelegateObject?, additionalData: [AnyHashable: Any]?) {
|
||||
Label.setUILabel(self, withJSON: json, delegate: delegateObject, additionalData: additionalData)
|
||||
|
||||
originalAttributedString = attributedText
|
||||
}
|
||||
|
||||
public func needsToBeConstrained() -> Bool {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
extension Label {
|
||||
|
||||
@ -604,8 +604,8 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt
|
||||
performAction = wButtonDelegate.button?(wSelf, shouldPerformActionWithMap: actionMap, additionalData: additionalData) ?? false
|
||||
}
|
||||
|
||||
if let wDelegate = weakDelegate as? CoreObjectActionLoadPresentDelegate, performAction {
|
||||
MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegate: wDelegate)
|
||||
if performAction {
|
||||
MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegate: weakDelegate as? CoreObjectActionLoadPresentDelegate)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -36,7 +36,7 @@
|
||||
}
|
||||
|
||||
- (void)setupView {
|
||||
|
||||
self.preservesSuperviewLayoutMargins = YES;
|
||||
}
|
||||
|
||||
- (void)updateView:(CGFloat)size {
|
||||
|
||||
@ -20,7 +20,8 @@
|
||||
|
||||
static const CGFloat FaultTolerance = 20.f;
|
||||
static const CGFloat CheckBoxHeightWidth = 18.0;
|
||||
@interface MVMCoreUICheckBox ()
|
||||
|
||||
@interface MVMCoreUICheckBox () <FormValidationProtocol, MVMCoreUIMoleculeViewProtocol>
|
||||
|
||||
@property (nonatomic, readwrite) BOOL isSelected;
|
||||
@property (weak, nonatomic) UIView *checkedSquare;
|
||||
@ -39,10 +40,45 @@ static const CGFloat CheckBoxHeightWidth = 18.0;
|
||||
@property (nullable, strong, nonatomic) NSLayoutConstraint *checkboxWidth;
|
||||
@property (nullable, strong, nonatomic) NSLayoutConstraint *checkboxHeight;
|
||||
|
||||
@property (nonatomic) BOOL isRequired;
|
||||
@property (nullable, strong, nonatomic) NSString *fieldKey;
|
||||
@property (nullable, strong, nonatomic) DelegateObject *delegate;
|
||||
|
||||
@end
|
||||
|
||||
@implementation MVMCoreUICheckBox
|
||||
|
||||
#pragma mark - MVMCoreUIMoleculeViewProtocol
|
||||
|
||||
- (BOOL)needsToBeConstrained {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (UIStackViewAlignment)moleculeAlignment {
|
||||
return UIStackViewAlignmentLeading;
|
||||
}
|
||||
|
||||
- (void)setWithJSON:(NSDictionary *)json delegateObject:(DelegateObject *)delegateObject additionalData:(NSDictionary *)additionalData {
|
||||
|
||||
[FormValidator setupValidationWithMolecule:self delegate:((MVMCoreUIDelegateObject *)delegateObject).formValidationProtocol];
|
||||
self.delegate = delegateObject;
|
||||
self.fieldKey = [json stringForKey:KeyFieldKey];
|
||||
self.isRequired = [json boolForKey:KeyRequired];
|
||||
|
||||
NSString *checkedColorHex = [json string:@"checkedColor"];
|
||||
NSString *unCheckedColorHex = [json string:@"unCheckedColor"];
|
||||
|
||||
UIColor *checkedColor = checkedColorHex ? [UIColor mfGetColorForHex:checkedColorHex]: [UIColor blackColor];
|
||||
UIColor *unCheckedColor = unCheckedColorHex ? [UIColor mfGetColorForHex:unCheckedColorHex]: [UIColor clearColor];
|
||||
|
||||
[self setupWithCheckedColor:checkedColor
|
||||
unCheckColor:unCheckedColor
|
||||
label:[json dict:KeyLabel]
|
||||
delegateObject:delegateObject
|
||||
additionalData: additionalData];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - convenient class methods
|
||||
|
||||
+ (instancetype)mfCheckBox {
|
||||
@ -69,8 +105,33 @@ static const CGFloat CheckBoxHeightWidth = 18.0;
|
||||
return checkBox;
|
||||
}
|
||||
|
||||
#pragma mark - FormValidationProtocol
|
||||
|
||||
- (BOOL)isValidField {
|
||||
if (self.isRequired) {
|
||||
return self.isSelected;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
- (nullable NSString *)formFieldName {
|
||||
return self.fieldKey;
|
||||
}
|
||||
|
||||
- (nullable id)formFieldValue {
|
||||
return @(self.isSelected);
|
||||
}
|
||||
|
||||
#pragma mark - inits
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
[self setupView];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithCheckedColor:(UIColor *)checkedColor unCheckColor:(UIColor *)unCheckedColor text:(NSString *)text {
|
||||
if (self = [super init]) {
|
||||
[self setupWithCheckedColor:checkedColor unCheckColor:unCheckedColor text:text];
|
||||
@ -207,17 +268,25 @@ static const CGFloat CheckBoxHeightWidth = 18.0;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setupWithCheckedColor:(UIColor *)checkedColor unCheckColor:(UIColor *)unCheckedColor {
|
||||
if (checkedColor) {
|
||||
self.checkedColor = checkedColor;
|
||||
}
|
||||
if (unCheckedColor) {
|
||||
self.unCheckedColor = unCheckedColor;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setupWithCheckedColor:(UIColor *)checkedColor unCheckColor:(UIColor *)unCheckedColor text:(NSString *)text {
|
||||
[self setupView];
|
||||
if (checkedColor) {
|
||||
self.checkedColor = checkedColor;
|
||||
}
|
||||
if (unCheckedColor) {
|
||||
self.unCheckedColor = unCheckedColor;
|
||||
}
|
||||
[self setupWithCheckedColor:checkedColor unCheckColor:unCheckedColor];
|
||||
[self setDescriptionText:text];
|
||||
}
|
||||
|
||||
- (void)setupWithCheckedColor:(UIColor *)checkedColor unCheckColor:(UIColor *)unCheckedColor label:(NSDictionary *)labelJson delegateObject:(DelegateObject *)delegateObject additionalData:(NSDictionary *)additionalData {
|
||||
[self setupWithCheckedColor:checkedColor unCheckColor:unCheckedColor];
|
||||
[self.descriptionLabel setWithJSON:labelJson delegateObject:delegateObject additionalData:additionalData];
|
||||
}
|
||||
|
||||
- (void)updateView:(CGFloat)size {
|
||||
[MVMCoreDispatchUtility performBlockOnMainThread:^{
|
||||
[self.descriptionLabel updateView:size];
|
||||
@ -254,7 +323,7 @@ static const CGFloat CheckBoxHeightWidth = 18.0;
|
||||
[self setSelected:selected animated:animated runBlock:YES];
|
||||
}
|
||||
|
||||
- (void)setSelected:(BOOL)selected animated:(BOOL)animated runBlock:(BOOL)runBlock{
|
||||
- (void)setSelected:(BOOL)selected animated:(BOOL)animated runBlock:(BOOL)runBlock {
|
||||
[self addAccessibilityLabel:selected];
|
||||
|
||||
self.isSelected = selected;
|
||||
@ -272,6 +341,9 @@ static const CGFloat CheckBoxHeightWidth = 18.0;
|
||||
} completion:nil];
|
||||
[self.checkMark updateCheckSelected:NO animated:animated];
|
||||
}
|
||||
|
||||
FormValidator *formValidator = ((MVMCoreUIDelegateObject *)self.delegate).formValidationProtocol.formValidatorModel;
|
||||
[formValidator enableByValidation];
|
||||
}
|
||||
|
||||
- (void)setColor:(nullable UIColor *)color forState:(UIControlState)state {
|
||||
|
||||
@ -26,6 +26,9 @@
|
||||
// Returns a view with the provided view as a subview, pinned.
|
||||
+ (nonnull ViewConstrainingView *)viewConstrainingView:(nonnull UIView *)view;
|
||||
|
||||
// Can be initialized with a molecule to constrain
|
||||
- (nullable instancetype)initWithMolecule:(nonnull UIView <MVMCoreUIMoleculeViewProtocol>*)molecule alignment:(UIStackViewAlignment)alignment;
|
||||
|
||||
// Use these to sets the constants, because subclasses may align differently.
|
||||
- (void)setPinConstantsWithInsets:(UIEdgeInsets)insets;
|
||||
- (void)setTopPinConstant:(CGFloat)top left:(CGFloat)left bottom:(CGFloat)bottom right:(CGFloat)right;
|
||||
@ -47,4 +50,7 @@
|
||||
// For setting up the view.
|
||||
- (void)setupView;
|
||||
|
||||
// Add a view to be constrained in this view.
|
||||
- (void)addConstrainedView:(nonnull UIView *)view;
|
||||
|
||||
@end
|
||||
|
||||
@ -9,69 +9,50 @@
|
||||
#import "ViewConstrainingView.h"
|
||||
@import MVMCore.MVMCoreConstants;
|
||||
@import MVMCore.MVMCoreDispatchUtility;
|
||||
#import "NSLayoutConstraint+MFConvenience.h"
|
||||
#import "MFStyler.h"
|
||||
|
||||
@interface ViewConstrainingView ()
|
||||
@property (weak, nullable, nonatomic) UIView *constrainedView;
|
||||
@property (weak, nullable, nonatomic) UIView <MVMCoreUIMoleculeViewProtocol>*molecule;
|
||||
@end
|
||||
|
||||
@implementation ViewConstrainingView
|
||||
|
||||
- (nullable instancetype)initWithMolecule:(nonnull UIView <MVMCoreUIMoleculeViewProtocol>*)molecule alignment:(UIStackViewAlignment)alignment {
|
||||
if (self = [super init]) {
|
||||
if (!molecule.superview) {
|
||||
[self addConstrainedView:molecule alignment:alignment];
|
||||
[self setAsMolecule];
|
||||
}
|
||||
self.molecule = molecule;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (nonnull ViewConstrainingView *)emptyView {
|
||||
ViewConstrainingView *view = [[ViewConstrainingView alloc] initWithFrame:CGRectZero];
|
||||
view.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
view.backgroundColor = [UIColor clearColor];
|
||||
return view;
|
||||
}
|
||||
|
||||
|
||||
+ (nonnull ViewConstrainingView *)viewConstrainingView:(UIView *)view {
|
||||
ViewConstrainingView *constrainingView = [[ViewConstrainingView alloc] initWithFrame:CGRectZero];
|
||||
constrainingView.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
constrainingView.backgroundColor = [UIColor clearColor];
|
||||
|
||||
view.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
[constrainingView addSubview:view];
|
||||
constrainingView.constrainedView = view;
|
||||
|
||||
NSLayoutConstraint *leftPin = [view.leftAnchor constraintEqualToAnchor:constrainingView.leftAnchor];
|
||||
constrainingView.leftPin = leftPin;
|
||||
leftPin.active = YES;
|
||||
|
||||
NSLayoutConstraint *topPin = [view.topAnchor constraintEqualToAnchor:constrainingView.topAnchor];
|
||||
constrainingView.topPin = topPin;
|
||||
topPin.active = YES;
|
||||
|
||||
NSLayoutConstraint *bottomPin = [constrainingView.bottomAnchor constraintEqualToAnchor:view.bottomAnchor];
|
||||
constrainingView.bottomPin = bottomPin;
|
||||
bottomPin.active = YES;
|
||||
|
||||
NSLayoutConstraint *rightPin = [constrainingView.rightAnchor constraintEqualToAnchor:view.rightAnchor];
|
||||
constrainingView.rightPin = rightPin;
|
||||
rightPin.active = YES;
|
||||
|
||||
[constrainingView addConstrainedView:view];
|
||||
return constrainingView;
|
||||
}
|
||||
|
||||
- (void)pinToSuperView {
|
||||
|
||||
// Align left and right constants.
|
||||
NSLayoutConstraint *leftPin = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.superview attribute:NSLayoutAttributeLeft multiplier:1.0 constant:0];
|
||||
self.leftPin = leftPin;
|
||||
leftPin.active = YES;
|
||||
|
||||
NSLayoutConstraint *topPin = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.superview attribute:NSLayoutAttributeTop multiplier:1.0 constant:0];
|
||||
self.topPin = topPin;
|
||||
topPin.active = YES;
|
||||
|
||||
NSLayoutConstraint *bottomPin = [NSLayoutConstraint constraintWithItem:self.superview attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0];
|
||||
self.bottomPin = bottomPin;
|
||||
bottomPin.active = YES;
|
||||
|
||||
NSLayoutConstraint *rightPin = [NSLayoutConstraint constraintWithItem:self.superview attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeRight multiplier:1.0 constant:0];
|
||||
self.rightPin = rightPin;
|
||||
rightPin.active = YES;
|
||||
NSDictionary *dictionary = [NSLayoutConstraint constraintPinSubviewToSuperview:self];
|
||||
self.leftPin = dictionary[ConstraintLeading];
|
||||
self.topPin = dictionary[ConstraintTop];
|
||||
self.bottomPin = dictionary[ConstraintBot];
|
||||
self.rightPin = dictionary[ConstraintTrailing];
|
||||
}
|
||||
|
||||
|
||||
- (void)setPinConstantsWithInsets:(UIEdgeInsets)insets {
|
||||
[self setTopPinConstant:insets.top left:insets.left bottom:insets.bottom right:insets.right];
|
||||
}
|
||||
@ -115,6 +96,34 @@
|
||||
self.backgroundColor = [UIColor clearColor];
|
||||
}
|
||||
|
||||
- (void)addConstrainedView:(nonnull UIView *)view alignment:(UIStackViewAlignment)alignment {
|
||||
view.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
[self addSubview:view];
|
||||
self.constrainedView = view;
|
||||
|
||||
NSLayoutRelation leftRelation;
|
||||
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 {
|
||||
[self addConstrainedView:view alignment:UIStackViewAlignmentFill];
|
||||
}
|
||||
|
||||
- (void)setupView {
|
||||
[super setupView];
|
||||
self.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
@ -131,6 +140,7 @@
|
||||
CGFloat padding = [MFStyler defaultHorizontalPaddingForSize:size];
|
||||
[self setLeftPinConstant:padding];
|
||||
[self setRightPinConstant:padding];
|
||||
[MFStyler setDefaultMarginsForView:self size:size];
|
||||
}];
|
||||
}
|
||||
}
|
||||
@ -138,6 +148,15 @@
|
||||
#pragma mark - MVMCoreUIMoleculeViewProtocol
|
||||
|
||||
- (void)setAsMolecule {
|
||||
self.updateViewHorizontalDefaults = YES;
|
||||
}
|
||||
|
||||
- (void)setWithJSON:(NSDictionary *)json delegateObject:(DelegateObject *)delegateObject additionalData:(NSDictionary *)additionalData {
|
||||
[super setWithJSON:json delegateObject:delegateObject additionalData:additionalData];
|
||||
if (self.molecule) {
|
||||
[self.molecule setWithJSON:json delegateObject:delegateObject additionalData:additionalData];
|
||||
self.backgroundColor = self.molecule.backgroundColor;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@ -521,6 +521,10 @@
|
||||
} completion:completion];
|
||||
}
|
||||
|
||||
- (BOOL)viewRespectsSystemMinimumLayoutMargins {
|
||||
return NO;
|
||||
}
|
||||
|
||||
#pragma mark - UITextField Functions
|
||||
|
||||
// To Remove TextFields Bug: Keyboard is not dismissing after reaching textfield max length limit
|
||||
|
||||
255
MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift
Normal file
255
MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift
Normal file
@ -0,0 +1,255 @@
|
||||
//
|
||||
// ThreeLayerTableViewController.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Scott Pfeil on 4/18/19.
|
||||
// Copyright © 2019 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import MVMAnimationFramework
|
||||
|
||||
open class ThreeLayerTableViewController: MFProgrammaticTableViewController {
|
||||
// The three main views
|
||||
private var topView: UIView?
|
||||
private var bottomView: UIView?
|
||||
private var headerView: UIView?
|
||||
private var footerView: UIView?
|
||||
private var safeAreaView: UIView?
|
||||
var useMargins: Bool = true
|
||||
var bottomViewOutsideOfScrollArea: Bool = false
|
||||
private var topViewBottomConstraint: NSLayoutConstraint?
|
||||
private var bottomViewTopConstraint: NSLayoutConstraint?
|
||||
|
||||
//MARK: - MVMCoreViewProtocol
|
||||
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()
|
||||
}
|
||||
if let bottomView = bottomView as? MVMCoreViewProtocol {
|
||||
bottomView.updateView(width)
|
||||
showFooter()
|
||||
}
|
||||
self.tableView?.reloadData()
|
||||
}
|
||||
|
||||
//MARK: - MFViewController
|
||||
open override func newDataBuildScreen() {
|
||||
super.newDataBuildScreen()
|
||||
createViewForTableHeader()
|
||||
createViewForTableFooter()
|
||||
tableView?.reloadData()
|
||||
}
|
||||
|
||||
override open func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
setToHaveNoSectionHeadersFooters()
|
||||
// Do any additional setup after loading the view.
|
||||
}
|
||||
|
||||
//MARK: - Spacing
|
||||
// If both are subclassed to return a value, then the buttons will not be pinned towards the bottom because neither spacing would try to fill the screen.
|
||||
/// Space between the top view and the table sections, nil to fill. 0 default
|
||||
open func spaceBelowTopView() -> CGFloat? {
|
||||
return 0
|
||||
}
|
||||
|
||||
/// Space between the bottom view and the table sections, nil to fill. nil default
|
||||
open func spaceAboveBottomView() -> CGFloat? {
|
||||
return nil
|
||||
}
|
||||
|
||||
/// can override to return a minimum fill space.
|
||||
open func minimumFillSpace() -> CGFloat {
|
||||
return 0
|
||||
}
|
||||
|
||||
open override func updateViewConstraints() {
|
||||
super.updateViewConstraints()
|
||||
guard let tableView = tableView else {
|
||||
return
|
||||
}
|
||||
|
||||
let minimumSpace: CGFloat = minimumFillSpace()
|
||||
var currentSpace: CGFloat = 0
|
||||
var totalMinimumSpace: CGFloat = 0
|
||||
|
||||
var fillTop = false
|
||||
if spaceBelowTopView() == nil, self.tableView?.tableHeaderView != nil {
|
||||
fillTop = true
|
||||
currentSpace += topViewBottomConstraint?.constant ?? 0
|
||||
totalMinimumSpace += minimumSpace
|
||||
}
|
||||
|
||||
var fillBottom = false
|
||||
if spaceAboveBottomView() == nil, !bottomViewOutsideOfScrollArea, self.tableView?.tableFooterView != nil {
|
||||
fillBottom = true
|
||||
currentSpace += bottomViewTopConstraint?.constant ?? 0
|
||||
totalMinimumSpace += minimumSpace
|
||||
}
|
||||
|
||||
guard fillTop || fillBottom else {
|
||||
return
|
||||
}
|
||||
let newSpace = MVMCoreUIUtility.getVariableConstraintHeight(currentSpace, in: tableView, minimumHeight: totalMinimumSpace)
|
||||
|
||||
// If the bottom view is outside of the scroll, then only the top view constraint is being used, so we have to double it to account for the bottom constraint not being there when we compare to the new value.
|
||||
var currentSpaceForCompare: CGFloat = currentSpace
|
||||
if fillTop && bottomViewOutsideOfScrollArea {
|
||||
currentSpaceForCompare = currentSpace * 2;
|
||||
}
|
||||
|
||||
if !MVMCoreGetterUtility.cgfequalwiththreshold(newSpace, currentSpaceForCompare, 0.1) {
|
||||
if fillTop && fillBottom {
|
||||
// space both
|
||||
let half = newSpace / 2
|
||||
topViewBottomConstraint?.constant = half
|
||||
bottomViewTopConstraint?.constant = half
|
||||
showHeader()
|
||||
showFooter()
|
||||
} 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 {
|
||||
topViewBottomConstraint?.constant = newSpace / 2
|
||||
} else {
|
||||
topViewBottomConstraint?.constant = newSpace
|
||||
}
|
||||
showHeader()
|
||||
} else if fillBottom {
|
||||
// Only bottom is spaced.
|
||||
bottomViewTopConstraint?.constant = newSpace
|
||||
showFooter()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//MARK: - Header Footer
|
||||
/// Gets the top view and adds it to a spacing view, headerView, and then calls showHeader.
|
||||
open func createViewForTableHeader() {
|
||||
let topView = viewForTop()
|
||||
self.topView = topView
|
||||
|
||||
let headerView = MVMCoreUICommonViewsUtility.commonView()
|
||||
headerView.addSubview(topView)
|
||||
topView.topAnchor.constraint(equalTo: headerView.topAnchor).isActive = true
|
||||
topView.leftAnchor.constraint(equalTo: headerView.leftAnchor).isActive = true
|
||||
headerView.rightAnchor.constraint(equalTo: topView.rightAnchor).isActive = true
|
||||
topViewBottomConstraint = headerView.bottomAnchor.constraint(equalTo: topView.bottomAnchor, constant: spaceBelowTopView() ?? 0)
|
||||
topViewBottomConstraint?.isActive = true
|
||||
self.headerView = headerView
|
||||
showHeader()
|
||||
}
|
||||
|
||||
/// Gets the bottom view and adds it to a spacing view, footerView, and then calls showFooter.
|
||||
open func createViewForTableFooter() {
|
||||
let bottomView = viewForBottom()
|
||||
self.bottomView = bottomView
|
||||
|
||||
let footerView = MVMCoreUICommonViewsUtility.commonView()
|
||||
footerView.addSubview(bottomView)
|
||||
bottomViewTopConstraint = bottomView.topAnchor.constraint(equalTo: footerView.topAnchor, constant: spaceAboveBottomView() ?? 0)
|
||||
bottomViewTopConstraint?.isActive = true
|
||||
bottomView.leftAnchor.constraint(equalTo: footerView.leftAnchor).isActive = true
|
||||
footerView.rightAnchor.constraint(equalTo: bottomView.rightAnchor).isActive = true
|
||||
footerView.bottomAnchor.constraint(equalTo: bottomView.bottomAnchor).isActive = true
|
||||
self.footerView = footerView
|
||||
showFooter()
|
||||
}
|
||||
|
||||
/// Takes the current headerView and adds it to the tableHeaderView
|
||||
func showHeader() {
|
||||
headerView?.removeFromSuperview()
|
||||
tableView?.tableHeaderView = nil
|
||||
guard let headerView = headerView else {
|
||||
return
|
||||
}
|
||||
|
||||
// This extra view is needed because of the wonkiness of apple's table header. Things breaks if using autolayout.
|
||||
MVMCoreUIUtility.sizeView(toFit: headerView)
|
||||
let tableHeaderView = UIView(frame: CGRect(x: 0, y: 0, width: MVMCoreUIUtility.getWidth(), height: headerView.frame.height))
|
||||
tableHeaderView.addSubview(headerView)
|
||||
NSLayoutConstraint.constraintPinSubview(toSuperview: headerView)
|
||||
tableView?.tableHeaderView = tableHeaderView
|
||||
}
|
||||
|
||||
/// Takes the current footerView and adds it to the tableFooterView
|
||||
func showFooter() {
|
||||
footerView?.removeFromSuperview()
|
||||
safeAreaView?.removeFromSuperview()
|
||||
guard let footerView = footerView, let tableView = tableView else {
|
||||
return
|
||||
}
|
||||
|
||||
if bottomViewOutsideOfScrollArea {
|
||||
// put bottom view outside of scrolling area.
|
||||
bottomConstraint?.isActive = false
|
||||
view.addSubview(footerView)
|
||||
footerView.topAnchor.constraint(equalTo: tableView.bottomAnchor).isActive = true
|
||||
footerView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
|
||||
view.rightAnchor.constraint(equalTo: footerView.rightAnchor).isActive = true
|
||||
if #available(iOS 11.0, *) {
|
||||
view.safeAreaLayoutGuide.bottomAnchor.constraint(equalTo: footerView.bottomAnchor).isActive = true
|
||||
safeAreaView = MVMCoreUICommonViewsUtility.getAndSetupSafeAreaView(on: view)
|
||||
safeAreaView?.backgroundColor = bottomView?.backgroundColor
|
||||
} else {
|
||||
view.bottomAnchor.constraint(equalTo: footerView.bottomAnchor).isActive = true
|
||||
}
|
||||
} else {
|
||||
bottomConstraint?.isActive = true
|
||||
var y: CGFloat?
|
||||
if let tableFooterView = tableView.tableFooterView {
|
||||
// if footer already exists, use the same y location to avoid strange moving animation
|
||||
y = tableFooterView.frame.minY
|
||||
}
|
||||
|
||||
// This extra view is needed because of the wonkiness of apple's table footer. Things breaks if using autolayout.
|
||||
MVMCoreUIUtility.sizeView(toFit: footerView)
|
||||
let tableFooterView = UIView(frame: CGRect(x: 0, y: y ?? 0, width: MVMCoreUIUtility.getWidth(), height: footerView.frame.height))
|
||||
tableFooterView.addSubview(footerView)
|
||||
NSLayoutConstraint.constraintPinSubview(toSuperview: footerView)
|
||||
tableView.tableFooterView = tableFooterView
|
||||
}
|
||||
}
|
||||
|
||||
//MARK: - Functions to subclass
|
||||
/// Subclass for a top view.
|
||||
open func viewForTop() -> UIView {
|
||||
let view = MVMCoreUICommonViewsUtility.commonView()
|
||||
view.heightAnchor.constraint(equalToConstant: 0).isActive = true
|
||||
return view
|
||||
}
|
||||
|
||||
/// Subclass for a bottom view.
|
||||
open func viewForBottom() -> UIView {
|
||||
let view = MVMCoreUICommonViewsUtility.commonView()
|
||||
view.heightAnchor.constraint(equalToConstant: 0).isActive = true
|
||||
return view
|
||||
}
|
||||
|
||||
//MARK: - Scrollview
|
||||
open override func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
||||
// To stop handscroll animation if animating after scroll
|
||||
stopHandScrollAnimation(true)
|
||||
}
|
||||
|
||||
deinit {
|
||||
tableView?.delegate = nil
|
||||
}
|
||||
|
||||
//MARK: - Animation
|
||||
open override func setupIntroAnimations() {
|
||||
if let topView = topView, topView.subviews.count > 0 {
|
||||
introAnimationManager?.addAnimation(animation: MVMAnimations.fadeUpAnimation(view: topView))
|
||||
}
|
||||
if let tableView = tableView {
|
||||
introAnimationManager?.addAnimation(animation: MVMAnimations.animateTableViewFadeInCells(tableView: tableView))
|
||||
}
|
||||
if let bottomView = bottomView, bottomView.subviews.count > 0 {
|
||||
introAnimationManager?.addAnimation(animation: MVMAnimations.fadeUpAnimation(view: bottomView))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -16,7 +16,7 @@ open class ThreeLayerViewController: ProgrammaticScrollViewController {
|
||||
var topView: UIView?
|
||||
var middleView: UIView?
|
||||
var bottomView: UIView?
|
||||
var useMargins: Bool = true
|
||||
var useMargins: Bool = false
|
||||
|
||||
// The bottom view can be put outside of the scrolling area.
|
||||
var bottomViewOutsideOfScroll = false
|
||||
|
||||
@ -31,8 +31,12 @@ extern NSString * _Nonnull const ConstraintWidth;
|
||||
|
||||
+ (nullable NSDictionary *)constraintPinSubview:(nullable UIView *)subview pinTop:(BOOL)pinTop pinBottom:(BOOL)pinBottom pinLeft:(BOOL)pinLeft pinRight:(BOOL)pinRight;
|
||||
|
||||
+ (nullable NSDictionary *)constraintPinSubview:(nullable UIView *)subview topRelation:(NSLayoutRelation)topRelation bottomRelation:(NSLayoutRelation)bottomRelation leftRelation:(NSLayoutRelation)leftRelation rightRelation:(NSLayoutRelation)rightRelation;
|
||||
|
||||
+ (nullable NSDictionary *)constraintPinSubview:(nullable UIView *)subview pinTop:(BOOL)pinTop topConstant:(CGFloat)topConstant pinBottom:(BOOL)pinBottom bottomConstant:(CGFloat)bottomConstant pinLeft:(BOOL)pinLeft leftConstant:(CGFloat)leftConstant pinRight:(BOOL)pinRight rightConstant:(CGFloat)rightConstant;
|
||||
|
||||
+ (nullable NSDictionary *)constraintPinSubview:(nullable UIView *)subview pinTop:(BOOL)pinTop topConstant:(CGFloat)topConstant topRelation:(NSLayoutRelation)topRelation pinBottom:(BOOL)pinBottom bottomConstant:(CGFloat)bottomConstant bottomRelation:(NSLayoutRelation)bottomRelation pinLeft:(BOOL)pinLeft leftConstant:(CGFloat)leftConstant leftRelation:(NSLayoutRelation)leftRelation pinRight:(BOOL)pinRight rightConstant:(CGFloat)rightConstant rightRelation:(NSLayoutRelation)rightRelation;
|
||||
|
||||
// Pin subview with 1 side
|
||||
+ (nullable NSDictionary *)constraintPinTopSubview:(nonnull UIView *)subview topConstant:(CGFloat)topConstant;
|
||||
+ (nullable NSDictionary *)constraintPinBottomSubview:(nonnull UIView *)subview bottomConstant:(CGFloat)bottomConstant;
|
||||
@ -57,6 +61,7 @@ extern NSString * _Nonnull const ConstraintWidth;
|
||||
|
||||
#pragma mark - With Margins
|
||||
|
||||
+ (nonnull NSDictionary <NSString *, NSLayoutConstraint *>*)pinViewToSuperview:(nonnull UIView *)subview useMargins:(BOOL)useMargins;
|
||||
+ (nonnull NSLayoutConstraint *)pinViewTopToSuperview:(nonnull UIView *)view useMargins:(BOOL)useMargins constant:(CGFloat)constant;
|
||||
+ (nonnull NSLayoutConstraint *)pinViewLeftToSuperview:(nonnull UIView *)view useMargins:(BOOL)useMargins constant:(CGFloat)constant;
|
||||
+ (nonnull NSLayoutConstraint *)pinViewRightToSuperview:(nonnull UIView *)view useMargins:(BOOL)useMargins constant:(CGFloat)constant;
|
||||
|
||||
@ -44,29 +44,37 @@ NSString *const ConstraintWidth = @"width";
|
||||
return [NSLayoutConstraint constraintPinSubview:subview pinTop:pinTop topConstant:0 pinBottom:pinBottom bottomConstant:0 pinLeft:pinLeft leftConstant:0 pinRight:pinRight rightConstant:0];
|
||||
}
|
||||
|
||||
+ (nullable NSDictionary *)constraintPinSubview:(nullable UIView *)subview topRelation:(NSLayoutRelation)topRelation bottomRelation:(NSLayoutRelation)bottomRelation leftRelation:(NSLayoutRelation)leftRelation rightRelation:(NSLayoutRelation)rightRelation {
|
||||
return [self constraintPinSubview:subview pinTop:YES topConstant:0 topRelation:topRelation pinBottom:YES bottomConstant:0 bottomRelation:bottomRelation pinLeft:YES leftConstant:0 leftRelation:leftRelation pinRight:YES rightConstant:0 rightRelation:rightRelation];
|
||||
}
|
||||
|
||||
+ (NSDictionary *)constraintPinSubview:(UIView *)subview pinTop:(BOOL)pinTop topConstant:(CGFloat)topConstant pinBottom:(BOOL)pinBottom bottomConstant:(CGFloat)bottomConstant pinLeft:(BOOL)pinLeft leftConstant:(CGFloat)leftConstant pinRight:(BOOL)pinRight rightConstant:(CGFloat)rightConstant {
|
||||
return [self constraintPinSubview:subview pinTop:pinTop topConstant:topConstant topRelation:NSLayoutRelationEqual pinBottom:pinBottom bottomConstant:bottomConstant bottomRelation:NSLayoutRelationEqual pinLeft:pinLeft leftConstant:leftConstant leftRelation:NSLayoutRelationEqual pinRight:pinRight rightConstant:rightConstant rightRelation:NSLayoutRelationEqual];
|
||||
}
|
||||
|
||||
+ (NSDictionary *)constraintPinSubview:(UIView *)subview pinTop:(BOOL)pinTop topConstant:(CGFloat)topConstant topRelation:(NSLayoutRelation)topRelation pinBottom:(BOOL)pinBottom bottomConstant:(CGFloat)bottomConstant bottomRelation:(NSLayoutRelation)bottomRelation pinLeft:(BOOL)pinLeft leftConstant:(CGFloat)leftConstant leftRelation:(NSLayoutRelation)leftRelation pinRight:(BOOL)pinRight rightConstant:(CGFloat)rightConstant rightRelation:(NSLayoutRelation)rightRelation {
|
||||
UIView *superview = subview.superview;
|
||||
NSMutableDictionary *constraintDic = [[NSMutableDictionary alloc] init];
|
||||
if (pinTop) {
|
||||
NSLayoutConstraint *top = [NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:superview attribute:NSLayoutAttributeTop multiplier:1 constant:topConstant];
|
||||
NSLayoutConstraint *top = [NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeTop relatedBy:topRelation toItem:superview attribute:NSLayoutAttributeTop multiplier:1 constant:topConstant];
|
||||
top.priority = 999;
|
||||
top.active = YES;
|
||||
[constraintDic setObject:top forKey:ConstraintTop];
|
||||
}
|
||||
if (pinBottom) {
|
||||
NSLayoutConstraint *bottom = [NSLayoutConstraint constraintWithItem:superview attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:subview attribute:NSLayoutAttributeBottom multiplier:1 constant:bottomConstant];
|
||||
NSLayoutConstraint *bottom = [NSLayoutConstraint constraintWithItem:superview attribute:NSLayoutAttributeBottom relatedBy:bottomRelation toItem:subview attribute:NSLayoutAttributeBottom multiplier:1 constant:bottomConstant];
|
||||
bottom.priority = 999;
|
||||
bottom.active = YES;
|
||||
[constraintDic setObject:bottom forKey:ConstraintBot];
|
||||
}
|
||||
if (pinLeft) {
|
||||
NSLayoutConstraint *leading = [NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:superview attribute:NSLayoutAttributeLeading multiplier:1 constant:leftConstant];
|
||||
NSLayoutConstraint *leading = [NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeLeading relatedBy:leftRelation toItem:superview attribute:NSLayoutAttributeLeading multiplier:1 constant:leftConstant];
|
||||
leading.priority = 999;
|
||||
leading.active = YES;
|
||||
[constraintDic setObject:leading forKey:ConstraintLeading];
|
||||
}
|
||||
if (pinRight) {
|
||||
NSLayoutConstraint *trailing = [NSLayoutConstraint constraintWithItem:superview attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:subview attribute:NSLayoutAttributeTrailing multiplier:1 constant:rightConstant];
|
||||
NSLayoutConstraint *trailing = [NSLayoutConstraint constraintWithItem:superview attribute:NSLayoutAttributeTrailing relatedBy:rightRelation toItem:subview attribute:NSLayoutAttributeTrailing multiplier:1 constant:rightConstant];
|
||||
trailing.priority = 999;
|
||||
trailing.active = YES;
|
||||
[constraintDic setObject:trailing forKey:ConstraintTrailing];
|
||||
@ -152,6 +160,14 @@ NSString *const ConstraintWidth = @"width";
|
||||
|
||||
#pragma mark - With Margins
|
||||
|
||||
+ (nonnull NSDictionary *)pinViewToSuperview:(nonnull UIView *)subview useMargins:(BOOL)useMargins {
|
||||
return @{ConstraintTop:[self pinViewTopToSuperview:subview useMargins:useMargins constant:0],
|
||||
ConstraintLeading:[self pinViewLeftToSuperview:subview useMargins:useMargins constant:0],
|
||||
ConstraintTrailing:[self pinViewRightToSuperview:subview useMargins:useMargins constant:0],
|
||||
ConstraintBot:[self pinViewBottomToSuperview:subview useMargins:useMargins constant:0],
|
||||
};
|
||||
}
|
||||
|
||||
+ (NSLayoutConstraint *)pinViewTopToSuperview:(UIView *)view useMargins:(BOOL)useMargins constant:(CGFloat)constant {
|
||||
return [view.topAnchor constraintEqualToAnchor:(useMargins ? view.superview.layoutMarginsGuide.topAnchor : view.superview.topAnchor) constant:constant];
|
||||
}
|
||||
|
||||
@ -25,6 +25,9 @@
|
||||
// true while panning
|
||||
@property (nonatomic) BOOL panning;
|
||||
|
||||
//set pannable percentage 0 to 1
|
||||
@property (nonatomic) CGFloat pannablePercentage;
|
||||
|
||||
// can be used to keep track of if we are ..
|
||||
@property (nonatomic) BOOL interactive;
|
||||
|
||||
|
||||
@ -8,8 +8,6 @@
|
||||
|
||||
#import "MFTabBarInteractor.h"
|
||||
|
||||
static CGFloat pannablePercentage = 0.15;
|
||||
|
||||
typedef NS_ENUM(NSUInteger, MFTabBarPanningDirection) {
|
||||
MFTabBarPanningDirectionLeft,
|
||||
MFTabBarPanningDirectionRight
|
||||
@ -33,6 +31,7 @@ typedef NS_ENUM(NSUInteger, MFTabBarPanningDirection) {
|
||||
|
||||
- (nullable instancetype)initWithViewController:(nullable UIViewController *)viewController delegate:(nullable id<MFSwipeNavigationProtocol>)delegate {
|
||||
if (self = [super init]) {
|
||||
self.pannablePercentage = 0.15;
|
||||
self.panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePanGesture:)];
|
||||
[viewController.view addGestureRecognizer:self.panGesture];
|
||||
self.delegate = delegate;
|
||||
@ -48,8 +47,8 @@ typedef NS_ENUM(NSUInteger, MFTabBarPanningDirection) {
|
||||
|
||||
// Simulates an edge gesture by only accepting pans at the edge of the screen. Needed because edge gesture doesn't work nicely with extended menus such as on ipad.
|
||||
CGRect frame = pan.view.frame;
|
||||
CGRect pannableFrameLeft = CGRectMake(frame.origin.x, frame.origin.y, frame.size.width*pannablePercentage, frame.size.height);
|
||||
CGRect pannableFrameRight = CGRectMake(frame.origin.x + frame.size.width*(1-pannablePercentage), frame.origin.y, frame.size.width*pannablePercentage, frame.size.height);
|
||||
CGRect pannableFrameLeft = CGRectMake(frame.origin.x, frame.origin.y, frame.size.width*self.pannablePercentage, frame.size.height);
|
||||
CGRect pannableFrameRight = CGRectMake(frame.origin.x + frame.size.width*(1-self.pannablePercentage), frame.origin.y, frame.size.width*self.pannablePercentage, frame.size.height);
|
||||
|
||||
switch (pan.state) {
|
||||
case UIGestureRecognizerStateBegan:
|
||||
|
||||
@ -22,6 +22,6 @@ import Foundation
|
||||
// The Field name key value pair for sending to server
|
||||
@objc optional func formFieldName() -> String?
|
||||
|
||||
// The Feild value key value paid for sending to server
|
||||
@objc optional func formFieldValue() -> String?
|
||||
// The Field value key value pair for sending to server
|
||||
@objc optional func formFieldValue() -> Any?
|
||||
}
|
||||
|
||||
@ -19,6 +19,15 @@
|
||||
// Called after init to provide an early setter for any molecule specific logic
|
||||
- (void)setAsMolecule;
|
||||
|
||||
// Notifies the creator that the view needs to be constrained in a view.
|
||||
- (BOOL)needsToBeConstrained;
|
||||
|
||||
// The alignment for the molecule if constrained.
|
||||
- (UIStackViewAlignment)moleculeAlignment;
|
||||
|
||||
// For the molecule list to load more efficiently.
|
||||
+ (CGFloat)estimatedHeightForRow;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
@ -13,6 +13,7 @@ public class MoleculeStackView: MFView {
|
||||
var moleculesArray: [UIView]?
|
||||
var useMargins: Bool = false
|
||||
|
||||
// MARK: - Inits
|
||||
public override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
}
|
||||
@ -31,6 +32,7 @@ public class MoleculeStackView: MFView {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
// MARK: - MFViewProtocol
|
||||
public override func setupView() {
|
||||
super.setupView()
|
||||
translatesAutoresizingMaskIntoConstraints = false
|
||||
@ -48,17 +50,17 @@ public class MoleculeStackView: MFView {
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - MVMCoreUIMoleculeViewProtocol
|
||||
open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: DelegateObject?, additionalData: [AnyHashable: Any]?) {
|
||||
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
|
||||
guard let molecules = json?.arrayForKey("molecules") as? [[String: Any]] else {
|
||||
guard let molecules = json?.arrayForKey(KeyMolecules) as? [[String: Any]] else {
|
||||
return
|
||||
}
|
||||
|
||||
// Create the molecules and set the json.
|
||||
var moleculesArray = [] as [UIView]
|
||||
for moleculeJSON in molecules {
|
||||
if let name = moleculeJSON.optionalStringForKey("moleculeName"), let molecule = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeForName(name) {
|
||||
molecule.setWithJSON(moleculeJSON, delegateObject: delegateObject, additionalData: additionalData)
|
||||
if let molecule = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeForStack(withJSON: moleculeJSON, delegateObject: delegateObject) {
|
||||
moleculesArray.append(molecule)
|
||||
}
|
||||
}
|
||||
@ -70,12 +72,9 @@ public class MoleculeStackView: MFView {
|
||||
if let spacingBlock = spacingBlock {
|
||||
MVMCoreUIStackableViewController.populateView(self, withUIArray: moleculesArray, useMargins: useMargins, withSpacingBlock: spacingBlock)
|
||||
} else {
|
||||
let separation = json?.optionalCGFloatForKey("separation") ?? PaddingDefault
|
||||
MVMCoreUIStackableViewController.populateView(self, withUIArray: moleculesArray, useMargins: useMargins) { (object) -> UIEdgeInsets in
|
||||
if object as AnyObject? === moleculesArray.first {
|
||||
return UIEdgeInsets.zero
|
||||
} else {
|
||||
return UIEdgeInsets.init(top: PaddingTwo, left: 0, bottom: 0, right: 0)
|
||||
}
|
||||
return UIEdgeInsets.init(top: separation, left: 0, bottom: 0, right: 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
152
MVMCoreUI/Molecules/MoleculeTableViewCell.swift
Normal file
152
MVMCoreUI/Molecules/MoleculeTableViewCell.swift
Normal file
@ -0,0 +1,152 @@
|
||||
//
|
||||
// MoleculeTableViewCell.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Scott Pfeil on 4/18/19.
|
||||
// Copyright © 2019 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
@objcMembers open class MoleculeTableViewCell: UITableViewCell, MVMCoreViewProtocol, MVMCoreUIMoleculeViewProtocol {
|
||||
open var molecule: (UIView & MVMCoreUIMoleculeViewProtocol)?
|
||||
|
||||
// For the accessory view convenience.
|
||||
public var caretView: CaretView?
|
||||
private var caretViewWidthSizeObject: MFSizeObject?
|
||||
private var caretViewHeightSizeObject: MFSizeObject?
|
||||
|
||||
// For separation between cells.
|
||||
public var topSeparatorView: SeparatorView?
|
||||
public var bottomSeparatorView: SeparatorView?
|
||||
public enum SeparatorFrequency: String {
|
||||
case All = "all"
|
||||
case AllExceptTop = "allExceptTop"
|
||||
case AllExceptBottom = "allExceptBottom"
|
||||
case Between = "between"
|
||||
}
|
||||
|
||||
// MARK: - Inits
|
||||
public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
|
||||
super.init(style: style, reuseIdentifier: reuseIdentifier)
|
||||
setupView()
|
||||
}
|
||||
|
||||
public required init?(coder aDecoder: NSCoder) {
|
||||
super.init(coder: aDecoder)
|
||||
setupView()
|
||||
}
|
||||
|
||||
// MARK: - MFViewProtocol
|
||||
public func updateView(_ size: CGFloat) {
|
||||
MFStyler.setDefaultMarginsFor(self, size: size)
|
||||
if #available(iOS 11.0, *) {
|
||||
contentView.directionalLayoutMargins = directionalLayoutMargins
|
||||
topSeparatorView?.setLeftAndRightPinConstant(directionalLayoutMargins.leading)
|
||||
bottomSeparatorView?.setLeftAndRightPinConstant(directionalLayoutMargins.leading)
|
||||
} else {
|
||||
contentView.layoutMargins = layoutMargins
|
||||
topSeparatorView?.setLeftAndRightPinConstant(layoutMargins.left)
|
||||
bottomSeparatorView?.setLeftAndRightPinConstant(layoutMargins.left)
|
||||
}
|
||||
|
||||
if let molecule = molecule as? MVMCoreViewProtocol {
|
||||
molecule.updateView(size)
|
||||
}
|
||||
if let _ = accessoryView, let caretView = caretView, let widthObject = caretViewWidthSizeObject, let heightObject = caretViewHeightSizeObject {
|
||||
caretView.frame = CGRect(x: 0, y: 0, width: widthObject.getValueBased(onSize: size), height: heightObject.getValueBased(onSize: size))
|
||||
}
|
||||
topSeparatorView?.updateView(size)
|
||||
bottomSeparatorView?.updateView(size)
|
||||
}
|
||||
|
||||
public func setupView() {
|
||||
preservesSuperviewLayoutMargins = false
|
||||
contentView.preservesSuperviewLayoutMargins = false
|
||||
selectionStyle = .none
|
||||
}
|
||||
|
||||
// MARK: - MVMCoreUIMoleculeViewProtocol
|
||||
public func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) {
|
||||
guard let json = json else {
|
||||
return
|
||||
}
|
||||
if molecule == nil {
|
||||
if let moleculeView = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeForStack(withJSON: json, delegateObject: delegateObject) {
|
||||
contentView.addSubview(moleculeView)
|
||||
NSLayoutConstraint.activate(Array(NSLayoutConstraint.pinView(toSuperview: moleculeView, useMargins: moleculeView.needsToBeConstrained?() ?? false).values))
|
||||
molecule = moleculeView
|
||||
}
|
||||
} else {
|
||||
molecule?.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
|
||||
}
|
||||
backgroundColor = molecule?.backgroundColor
|
||||
}
|
||||
|
||||
// MARK: - Convenience
|
||||
/// Adds the standard mvm style caret to the accessory view
|
||||
public func addCaretViewAccessory() {
|
||||
guard accessoryView == nil else {
|
||||
return
|
||||
}
|
||||
let width: CGFloat = 6
|
||||
let height: CGFloat = 10
|
||||
caretView = CaretView(lineThickness: CaretView.thin)
|
||||
caretView?.frame = CGRect(x: 0, y: 0, width: width, height: height)
|
||||
caretViewWidthSizeObject = MFSizeObject(scalingStandardSize: width)
|
||||
caretViewHeightSizeObject = MFSizeObject(scalingStandardSize: height)
|
||||
accessoryView = caretView
|
||||
}
|
||||
|
||||
func addSeparatorsIfNeeded() {
|
||||
if topSeparatorView == nil {
|
||||
topSeparatorView = SeparatorView.separatorAdd(to: self, position: SeparatorPositionTop)
|
||||
topSeparatorView?.hide()
|
||||
}
|
||||
if bottomSeparatorView == nil {
|
||||
bottomSeparatorView = SeparatorView.separatorAdd(to: self, position: SeparatorPositionBot)
|
||||
bottomSeparatorView?.hide()
|
||||
}
|
||||
}
|
||||
|
||||
/// For when the separator between cells shows using json and frequency.
|
||||
public func setSeparatorWithJSON(_ json: [AnyHashable : Any]?, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?, indexPath: IndexPath) {
|
||||
guard let json = json else {
|
||||
return
|
||||
}
|
||||
addSeparatorsIfNeeded()
|
||||
topSeparatorView?.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
|
||||
bottomSeparatorView?.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
|
||||
if let separatorFrequencyString = json.optionalStringForKey("frequency"), let separatorFrequency = SeparatorFrequency(rawValue: separatorFrequencyString) {
|
||||
setSeparatorFrequency(separatorFrequency, indexPath: indexPath)
|
||||
}
|
||||
}
|
||||
|
||||
/// For when the separator between cells shows.
|
||||
public func setSeparatorFrequency(_ separatorFrequency: SeparatorFrequency, indexPath: IndexPath) {
|
||||
switch separatorFrequency {
|
||||
case .All:
|
||||
if indexPath.row == 0 {
|
||||
topSeparatorView?.show()
|
||||
} else {
|
||||
topSeparatorView?.hide()
|
||||
}
|
||||
bottomSeparatorView?.show()
|
||||
case .AllExceptBottom:
|
||||
topSeparatorView?.show()
|
||||
bottomSeparatorView?.hide()
|
||||
case .Between:
|
||||
if indexPath.row == 0 {
|
||||
topSeparatorView?.hide()
|
||||
} else {
|
||||
topSeparatorView?.show()
|
||||
}
|
||||
bottomSeparatorView?.hide()
|
||||
case .AllExceptTop:
|
||||
fallthrough
|
||||
default:
|
||||
topSeparatorView?.hide()
|
||||
bottomSeparatorView?.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -46,16 +46,16 @@ public class StandardFooterView: ViewConstrainingView {
|
||||
spaceBetweenButtons = textButton.topAnchor.constraint(equalTo: twoButtonView.bottomAnchor, constant: PaddingTwo)
|
||||
spaceBetweenButtons?.isActive = true
|
||||
|
||||
leftConstraintTwoButton = twoButtonView.leftAnchor.constraint(equalTo: leftAnchor)
|
||||
leftConstraintTwoButton = twoButtonView.leftAnchor.constraint(equalTo: layoutMarginsGuide.leftAnchor)
|
||||
leftConstraintTwoButton?.isActive = true
|
||||
|
||||
rightConstraintTwoButton = rightAnchor.constraint(equalTo: twoButtonView.rightAnchor)
|
||||
rightConstraintTwoButton = layoutMarginsGuide.rightAnchor.constraint(equalTo: twoButtonView.rightAnchor)
|
||||
rightConstraintTwoButton?.isActive = true
|
||||
|
||||
leftConstraintTextButton = textButton.leftAnchor.constraint(greaterThanOrEqualTo: leftAnchor)
|
||||
leftConstraintTextButton = textButton.leftAnchor.constraint(greaterThanOrEqualTo: layoutMarginsGuide.leftAnchor)
|
||||
leftConstraintTextButton?.isActive = true
|
||||
|
||||
rightConstraintTextButton = rightAnchor.constraint(greaterThanOrEqualTo: textButton.rightAnchor)
|
||||
rightConstraintTextButton = layoutMarginsGuide.rightAnchor.constraint(greaterThanOrEqualTo: textButton.rightAnchor)
|
||||
rightConstraintTextButton?.isActive = true
|
||||
|
||||
centerAlignTextButton = textButton.centerXAnchor.constraint(equalTo: centerXAnchor)
|
||||
@ -93,16 +93,6 @@ public class StandardFooterView: ViewConstrainingView {
|
||||
layoutIfNeeded()
|
||||
}
|
||||
|
||||
public override func setLeftPinConstant(_ constant: CGFloat) {
|
||||
leftConstraintTwoButton?.constant = constant
|
||||
leftConstraintTextButton?.constant = constant
|
||||
}
|
||||
|
||||
public override func setRightPinConstant(_ constant: CGFloat) {
|
||||
rightConstraintTwoButton?.constant = constant
|
||||
rightConstraintTextButton?.constant = constant
|
||||
}
|
||||
|
||||
open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: DelegateObject?, additionalData: [AnyHashable: Any]?) {
|
||||
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
|
||||
if let colorString = json?.optionalStringForKey(KeyBackgroundColor) {
|
||||
|
||||
@ -22,4 +22,7 @@
|
||||
- (nullable UIView <MVMCoreUIMoleculeViewProtocol>*)getMoleculeForName:(nonnull NSString *)name;
|
||||
- (nullable UIView <MVMCoreUIMoleculeViewProtocol>*)getMoleculeForJSON:(nonnull NSDictionary *)json delegateObject:(nullable DelegateObject *)delegateObject;
|
||||
|
||||
// Similar to above but also checks if the molecule needs to be constrained for a stack.
|
||||
- (nullable UIView <MVMCoreUIMoleculeViewProtocol>*)getMoleculeForStackWithJSON:(nonnull NSDictionary *)json delegateObject:(nullable DelegateObject *)delegateObject;
|
||||
|
||||
@end
|
||||
|
||||
@ -32,7 +32,8 @@
|
||||
@"standardFooter": StandardFooterView.class,
|
||||
@"caretView": CaretView.class,
|
||||
@"caretButton": CaretButton.class,
|
||||
@"textField" : MFTextField.class
|
||||
@"textField" : MFTextField.class,
|
||||
@"checkbox" : MVMCoreUICheckBox.class
|
||||
} mutableCopy];
|
||||
});
|
||||
return mapping;
|
||||
@ -45,18 +46,18 @@
|
||||
|
||||
- (nullable UIView <MVMCoreUIMoleculeViewProtocol>*)getMoleculeForName:(nonnull NSString *)name {
|
||||
Class class = [self.moleculeMapping objectForKey:name];
|
||||
if (class) {
|
||||
UIView <MVMCoreUIMoleculeViewProtocol>*view = [[class alloc] init];
|
||||
if ([view respondsToSelector:@selector(setAsMolecule)]) {
|
||||
[view setAsMolecule];
|
||||
}
|
||||
return view;
|
||||
if (!class) {
|
||||
return nil;
|
||||
}
|
||||
return nil;
|
||||
UIView <MVMCoreUIMoleculeViewProtocol>*molecule = [[class alloc] init];
|
||||
if ([molecule respondsToSelector:@selector(setAsMolecule)]) {
|
||||
[molecule setAsMolecule];
|
||||
}
|
||||
return molecule;
|
||||
}
|
||||
|
||||
- (nullable UIView <MVMCoreUIMoleculeViewProtocol>*)getMoleculeForJSON:(nonnull NSDictionary *)json delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject {
|
||||
NSString *moleculeName = [json string:@"moleculeName"];
|
||||
- (nullable UIView <MVMCoreUIMoleculeViewProtocol>*)getMoleculeForJSON:(nonnull NSDictionary *)json delegateObject:(nullable DelegateObject *)delegateObject {
|
||||
NSString *moleculeName = [json string:KeyMoleculeName];
|
||||
if (!moleculeName) {
|
||||
return nil;
|
||||
}
|
||||
@ -66,4 +67,17 @@
|
||||
}
|
||||
|
||||
|
||||
- (nullable UIView <MVMCoreUIMoleculeViewProtocol>*)getMoleculeForStackWithJSON:(nonnull NSDictionary *)json delegateObject:(nullable DelegateObject *)delegateObject {
|
||||
NSString *moleculeName = [json string:KeyMoleculeName];
|
||||
if (!moleculeName) {
|
||||
return nil;
|
||||
}
|
||||
UIView <MVMCoreUIMoleculeViewProtocol>*molecule = [self getMoleculeForName:moleculeName];
|
||||
if ([molecule respondsToSelector:@selector(needsToBeConstrained)] && [molecule needsToBeConstrained]) {
|
||||
molecule = [[ViewConstrainingView alloc] initWithMolecule:molecule alignment:[molecule respondsToSelector:@selector(moleculeAlignment)] ? [molecule moleculeAlignment] : UIStackViewAlignmentFill];
|
||||
}
|
||||
[molecule setWithJSON:json delegateObject:delegateObject additionalData:nil];
|
||||
return molecule;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@ -21,7 +21,8 @@
|
||||
viewControllerMapping = [@{
|
||||
@"textFieldListForm" : [[MVMCoreViewControllerProgrammaticMappingObject alloc] initWithClass:[TextFieldListFormViewController class]],
|
||||
@"moleculeStack" : [[MVMCoreViewControllerProgrammaticMappingObject alloc] initWithClass:[MoleculeStackTemplate class]],
|
||||
@"centerMoleculeStack" : [[MVMCoreViewControllerProgrammaticMappingObject alloc] initWithClass:[MoleculeStackCenteredTemplate class]]
|
||||
@"centerMoleculeStack" : [[MVMCoreViewControllerProgrammaticMappingObject alloc] initWithClass:[MoleculeStackCenteredTemplate class]],
|
||||
@"moleculeList" : [[MVMCoreViewControllerProgrammaticMappingObject alloc] initWithClass:[MoleculeListTemplate class]]
|
||||
} mutableCopy];
|
||||
});
|
||||
return viewControllerMapping;
|
||||
|
||||
68
MVMCoreUI/Templates/MoleculeListTemplate.swift
Normal file
68
MVMCoreUI/Templates/MoleculeListTemplate.swift
Normal file
@ -0,0 +1,68 @@
|
||||
//
|
||||
// MoleculeListTemplate.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Scott Pfeil on 4/18/19.
|
||||
// Copyright © 2019 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
open class MoleculeListTemplate: ThreeLayerTableViewController {
|
||||
|
||||
open override func registerWithTable() {
|
||||
super.registerWithTable()
|
||||
guard let molecules = loadObject?.pageJSON?.arrayForKey(KeyMolecules) else {
|
||||
return
|
||||
}
|
||||
for case let molecule as Dictionary<AnyHashable, Any> in molecules {
|
||||
if let moleculeName = molecule.optionalStringForKey(KeyMoleculeName) {
|
||||
tableView?.register(MoleculeTableViewCell.self, forCellReuseIdentifier: moleculeName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
open override func viewForTop() -> UIView {
|
||||
guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("header"), let molecule = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeForStack(withJSON: moleculeJSON, delegateObject: delegateObject()) else {
|
||||
return super.viewForTop()
|
||||
}
|
||||
return molecule
|
||||
}
|
||||
|
||||
override open func viewForBottom() -> UIView {
|
||||
guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("footer"), let molecule = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeForStack(withJSON: moleculeJSON, delegateObject: delegateObject()) else {
|
||||
return viewForBottom()
|
||||
}
|
||||
return molecule
|
||||
}
|
||||
|
||||
open override func newDataBuildScreen() {
|
||||
super.newDataBuildScreen()
|
||||
registerWithTable()
|
||||
}
|
||||
|
||||
open override func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
|
||||
if let moleculeName = loadObject?.pageJSON?.stringOptionalWithChainOfKeysOrIndexes([KeyMolecules,indexPath.row,KeyMoleculeName]), let theClass = MVMCoreUIMoleculeMappingObject.shared()?.moleculeMapping?[moleculeName] as? MVMCoreUIMoleculeViewProtocol.Type,
|
||||
let estimatedHeightForRow = theClass.estimatedHeightForRow {
|
||||
return estimatedHeightForRow()
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
open override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
return loadObject?.pageJSON?.arrayForKey(KeyMolecules).count ?? 0
|
||||
}
|
||||
|
||||
open override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
guard let molecule = loadObject?.pageJSON?.optionalDictionaryWithChainOfKeysOrIndexes([KeyMolecules,indexPath.row]),
|
||||
let moleculeName = molecule.optionalStringForKey(KeyMoleculeName),
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: moleculeName) as? MoleculeTableViewCell else {
|
||||
return UITableViewCell()
|
||||
}
|
||||
let delegate = delegateObject()
|
||||
cell.setWithJSON(molecule, delegateObject: delegate, additionalData: nil)
|
||||
cell.setSeparatorWithJSON(loadObject?.pageJSON?.optionalDictionaryForKey("separator"), delegateObject: delegate, additionalData: nil, indexPath: indexPath)
|
||||
cell.updateView(tableView.bounds.width)
|
||||
return cell
|
||||
}
|
||||
}
|
||||
@ -18,7 +18,7 @@ public class MoleculeStackCenteredTemplate: ThreeLayerViewController {
|
||||
|
||||
public override func viewForTop() -> UIView? {
|
||||
guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("header"),
|
||||
let molecule = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeForJSON(moleculeJSON, delegateObject: delegateObject()) else {
|
||||
let molecule = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeForStack(withJSON: moleculeJSON, delegateObject: delegateObject()) else {
|
||||
return nil
|
||||
}
|
||||
return molecule
|
||||
@ -26,7 +26,7 @@ public class MoleculeStackCenteredTemplate: ThreeLayerViewController {
|
||||
|
||||
override public func viewForBottom() -> UIView? {
|
||||
guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("footer"),
|
||||
let molecule = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeForJSON(moleculeJSON, delegateObject: delegateObject()) else {
|
||||
let molecule = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeForStack(withJSON: moleculeJSON, delegateObject: delegateObject()) else {
|
||||
return nil
|
||||
}
|
||||
return molecule
|
||||
|
||||
@ -12,11 +12,11 @@ public class MoleculeStackTemplate: ThreeLayerViewController {
|
||||
|
||||
|
||||
public override func spaceBetweenTopAndMiddle() -> CGFloat? {
|
||||
return PaddingTwo
|
||||
return 0
|
||||
}
|
||||
|
||||
public override func viewForTop() -> UIView? {
|
||||
guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("header"), let molecule = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeForJSON(moleculeJSON, delegateObject: delegateObject()) else {
|
||||
guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("header"), let molecule = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeForStack(withJSON: moleculeJSON, delegateObject: delegateObject()) else {
|
||||
return nil
|
||||
}
|
||||
return molecule
|
||||
@ -30,7 +30,7 @@ public class MoleculeStackTemplate: ThreeLayerViewController {
|
||||
}
|
||||
|
||||
override public func viewForBottom() -> UIView? {
|
||||
guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("footer"), let molecule = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeForJSON(moleculeJSON, delegateObject: delegateObject()) else {
|
||||
guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("footer"), let molecule = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeForStack(withJSON: moleculeJSON, delegateObject: delegateObject()) else {
|
||||
return nil
|
||||
}
|
||||
return molecule
|
||||
|
||||
@ -13,6 +13,9 @@
|
||||
|
||||
extern NSString * const KeyScreenHeading;
|
||||
|
||||
extern NSString * const KeyMolecules;
|
||||
extern NSString * const KeyMoleculeName;
|
||||
|
||||
extern NSString * const KeyDisableButton;
|
||||
|
||||
extern NSString * const KeyValue;
|
||||
@ -35,6 +38,9 @@ extern NSString * const KeyTextColor;
|
||||
extern NSString * const KeyIsHidden;
|
||||
extern NSString * const KeyIsOpaque;
|
||||
|
||||
extern NSString * const KeyFieldKey;
|
||||
extern NSString * const KeyRequired;
|
||||
|
||||
#pragma mark - Values
|
||||
|
||||
extern NSString * const StringY;
|
||||
|
||||
@ -12,12 +12,17 @@
|
||||
|
||||
NSString * const KeyScreenHeading = @"screenHeading";
|
||||
|
||||
NSString * const KeyMolecules = @"molecules";
|
||||
NSString * const KeyMoleculeName = @"moleculeName";
|
||||
|
||||
NSString * const KeyDisableButton = @"disableAction";
|
||||
|
||||
NSString * const KeyValue = @"value";
|
||||
NSString * const KeyLabel = @"label";
|
||||
NSString * const KeyDisable = @"disable";
|
||||
NSString * const KeyFieldName = @"fieldName";
|
||||
NSString * const KeyFieldKey = @"fieldKey";
|
||||
NSString * const KeyRequired = @"required";
|
||||
|
||||
NSString * const KeyHideMainMenu = @"hideMainMenu";
|
||||
NSString * const KeyProgressPercent = @"progressPercent";
|
||||
@ -34,6 +39,7 @@ NSString * const KeyTextColor = @"textColor";
|
||||
NSString * const KeyIsHidden = @"isHidden";
|
||||
NSString * const KeyIsOpaque = @"isOpaque";
|
||||
|
||||
|
||||
#pragma mark - Values
|
||||
|
||||
NSString * const StringY = @"Y";
|
||||
|
||||
Loading…
Reference in New Issue
Block a user