Merge branch 'develop' into feature/kevin

# Conflicts:
#	MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift
This commit is contained in:
Christiano, Kevin 2019-04-30 13:00:03 -04:00
commit 14f65b0cd3
25 changed files with 682 additions and 90 deletions

View File

@ -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 */,

View File

@ -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;
}
}

View File

@ -141,4 +141,12 @@
}
}
- (BOOL)needsToBeConstrained {
return YES;
}
- (UIStackViewAlignment)moleculeAlignment {
return UIStackViewAlignmentLeading;
}
@end

View File

@ -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;
}
}

View File

@ -275,7 +275,6 @@ public typealias ActionBlock = () -> Void
}
})
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))
}
@ -305,9 +304,12 @@ public typealias ActionBlock = () -> Void
@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;
}
}
// MARK: - UIControl Override

View File

@ -36,7 +36,7 @@
}
- (void)setupView {
self.preservesSuperviewLayoutMargins = YES;
}
- (void)updateView:(CGFloat)size {

View File

@ -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;
@ -41,6 +44,9 @@
// Pins all edges to its super. 0 constant
- (void)pinToSuperView;
// Add a view to be constrained in this view.
- (void)addConstrainedView:(nonnull UIView *)view;
// Resets all the constraints to default.
- (void)resetConstraints;

View File

@ -9,14 +9,27 @@
#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;
@ -28,48 +41,16 @@
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 {
@ -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

View File

@ -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

View 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))
}
}
}

View File

@ -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

View File

@ -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;

View File

@ -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];
}

View File

@ -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)
}
}
}

View 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()
}
}
}

View File

@ -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

View File

@ -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) {

View File

@ -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

View File

@ -45,18 +45,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 +66,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

View File

@ -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;

View 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
}
}

View File

@ -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

View File

@ -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

View File

@ -13,6 +13,9 @@
extern NSString * const KeyScreenHeading;
extern NSString * const KeyMolecules;
extern NSString * const KeyMoleculeName;
extern NSString * const KeyDisableButton;
extern NSString * const KeyValue;

View File

@ -12,6 +12,9 @@
NSString * const KeyScreenHeading = @"screenHeading";
NSString * const KeyMolecules = @"molecules";
NSString * const KeyMoleculeName = @"moleculeName";
NSString * const KeyDisableButton = @"disableAction";
NSString * const KeyValue = @"value";