diff --git a/MVMCoreUI/Atoms/Buttons/CaretButton.swift b/MVMCoreUI/Atoms/Buttons/CaretButton.swift index 47697980..c8bf3fdf 100644 --- a/MVMCoreUI/Atoms/Buttons/CaretButton.swift +++ b/MVMCoreUI/Atoms/Buttons/CaretButton.swift @@ -135,4 +135,8 @@ open class CaretButton: MFCustomButton, MVMCoreUIMoleculeViewProtocol { public func needsToBeConstrained() -> Bool { return true } + + open func moleculeAlignment() -> UIStackView.Alignment { + return UIStackView.Alignment.leading; + } } diff --git a/MVMCoreUI/Atoms/Buttons/MFTextButton.m b/MVMCoreUI/Atoms/Buttons/MFTextButton.m index 96a99a18..d78df33d 100644 --- a/MVMCoreUI/Atoms/Buttons/MFTextButton.m +++ b/MVMCoreUI/Atoms/Buttons/MFTextButton.m @@ -145,4 +145,8 @@ return YES; } +- (UIStackViewAlignment)moleculeAlignment { + return UIStackViewAlignmentLeading; +} + @end diff --git a/MVMCoreUI/Atoms/Views/CaretView.swift b/MVMCoreUI/Atoms/Views/CaretView.swift index fff6181e..2be52f11 100644 --- a/MVMCoreUI/Atoms/Views/CaretView.swift +++ b/MVMCoreUI/Atoms/Views/CaretView.swift @@ -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() } @@ -123,4 +132,8 @@ open class CaretView: MFView { open override func needsToBeConstrained() -> Bool { return true } + + open override func moleculeAlignment() -> UIStackView.Alignment { + return UIStackView.Alignment.leading; + } } diff --git a/MVMCoreUI/Atoms/Views/MFView.m b/MVMCoreUI/Atoms/Views/MFView.m index 4bd73485..b22a5674 100644 --- a/MVMCoreUI/Atoms/Views/MFView.m +++ b/MVMCoreUI/Atoms/Views/MFView.m @@ -36,7 +36,7 @@ } - (void)setupView { - + self.preservesSuperviewLayoutMargins = YES; } - (void)updateView:(CGFloat)size { diff --git a/MVMCoreUI/Atoms/Views/ViewConstrainingView.h b/MVMCoreUI/Atoms/Views/ViewConstrainingView.h index 377c7821..528a79e6 100644 --- a/MVMCoreUI/Atoms/Views/ViewConstrainingView.h +++ b/MVMCoreUI/Atoms/Views/ViewConstrainingView.h @@ -27,7 +27,7 @@ + (nonnull ViewConstrainingView *)viewConstrainingView:(nonnull UIView *)view; // Can be initialized with a molecule to constrain -- (nullable instancetype)initWithMolecule:(nonnull UIView *)molecule; +- (nullable instancetype)initWithMolecule:(nonnull UIView *)molecule alignment:(UIStackViewAlignment)alignment; // Use these to sets the constants, because subclasses may align differently. - (void)setPinConstantsWithInsets:(UIEdgeInsets)insets; diff --git a/MVMCoreUI/Atoms/Views/ViewConstrainingView.m b/MVMCoreUI/Atoms/Views/ViewConstrainingView.m index d14163a6..861db8cd 100644 --- a/MVMCoreUI/Atoms/Views/ViewConstrainingView.m +++ b/MVMCoreUI/Atoms/Views/ViewConstrainingView.m @@ -9,6 +9,7 @@ #import "ViewConstrainingView.h" @import MVMCore.MVMCoreConstants; @import MVMCore.MVMCoreDispatchUtility; +#import "NSLayoutConstraint+MFConvenience.h" #import "MFStyler.h" @interface ViewConstrainingView () @@ -18,10 +19,11 @@ @implementation ViewConstrainingView -- (nullable instancetype)initWithMolecule:(nonnull UIView *)molecule { +- (nullable instancetype)initWithMolecule:(nonnull UIView *)molecule alignment:(UIStackViewAlignment)alignment { if (self = [super init]) { if (!molecule.superview) { - [self addConstrainedView:molecule]; + [self addConstrainedView:molecule alignment:alignment]; + [self setAsMolecule]; } self.molecule = molecule; } @@ -44,23 +46,11 @@ } - (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 { @@ -106,26 +96,32 @@ self.backgroundColor = [UIColor clearColor]; } -- (void)addConstrainedView:(nonnull UIView *)view { +- (void)addConstrainedView:(nonnull UIView *)view alignment:(UIStackViewAlignment)alignment { view.translatesAutoresizingMaskIntoConstraints = NO; [self addSubview:view]; self.constrainedView = view; - NSLayoutConstraint *leftPin = [view.leftAnchor constraintEqualToAnchor:self.leftAnchor]; - self.leftPin = leftPin; - leftPin.active = YES; - - NSLayoutConstraint *topPin = [view.topAnchor constraintEqualToAnchor:self.topAnchor]; - self.topPin = topPin; - topPin.active = YES; - - NSLayoutConstraint *bottomPin = [self.bottomAnchor constraintEqualToAnchor:view.bottomAnchor]; - self.bottomPin = bottomPin; - bottomPin.active = YES; - - NSLayoutConstraint *rightPin = [self.rightAnchor constraintEqualToAnchor:view.rightAnchor]; - self.rightPin = rightPin; - rightPin.active = YES; + 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 { @@ -153,9 +149,6 @@ - (void)setAsMolecule { self.updateViewHorizontalDefaults = YES; - if ([self.molecule respondsToSelector:@selector(setAsMolecule)]) { - [self.molecule setAsMolecule]; - } } - (void)setWithJSON:(NSDictionary *)json delegateObject:(DelegateObject *)delegateObject additionalData:(NSDictionary *)additionalData { diff --git a/MVMCoreUI/Categories/NSLayoutConstraint+MFConvenience.h b/MVMCoreUI/Categories/NSLayoutConstraint+MFConvenience.h index c8e12cae..0d0d281c 100644 --- a/MVMCoreUI/Categories/NSLayoutConstraint+MFConvenience.h +++ b/MVMCoreUI/Categories/NSLayoutConstraint+MFConvenience.h @@ -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 *)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; diff --git a/MVMCoreUI/Categories/NSLayoutConstraint+MFConvenience.m b/MVMCoreUI/Categories/NSLayoutConstraint+MFConvenience.m index 39a315c1..72aad96f 100644 --- a/MVMCoreUI/Categories/NSLayoutConstraint+MFConvenience.m +++ b/MVMCoreUI/Categories/NSLayoutConstraint+MFConvenience.m @@ -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]; } diff --git a/MVMCoreUI/Molecules/MoleculeStackView.swift b/MVMCoreUI/Molecules/MoleculeStackView.swift index a43a6a94..10e048d3 100644 --- a/MVMCoreUI/Molecules/MoleculeStackView.swift +++ b/MVMCoreUI/Molecules/MoleculeStackView.swift @@ -57,8 +57,7 @@ public class MoleculeStackView: MFView { // 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) } } diff --git a/MVMCoreUI/Molecules/MoleculeTableViewCell.swift b/MVMCoreUI/Molecules/MoleculeTableViewCell.swift index 21b05a22..4cd0dfd5 100644 --- a/MVMCoreUI/Molecules/MoleculeTableViewCell.swift +++ b/MVMCoreUI/Molecules/MoleculeTableViewCell.swift @@ -10,11 +10,42 @@ import UIKit @objcMembers open class MoleculeTableViewCell: UITableViewCell, MVMCoreViewProtocol, MVMCoreUIMoleculeViewProtocol { var molecule: (UIView & MVMCoreUIMoleculeViewProtocol)? + + 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() + } + + // For the accessory view convenience. + var caretView: CaretView? + private var caretViewWidthSizeObject: MFSizeObject? + private var caretViewHeightSizeObject: MFSizeObject? public func updateView(_ size: CGFloat) { + MFStyler.setDefaultMarginsFor(self, size: size) + if #available(iOS 11.0, *) { + contentView.directionalLayoutMargins = directionalLayoutMargins + } else { + contentView.layoutMargins = layoutMargins + } + 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)) + } + } + + public func setupView() { + preservesSuperviewLayoutMargins = false + contentView.preservesSuperviewLayoutMargins = false + selectionStyle = .none } public func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) { @@ -22,13 +53,28 @@ import UIKit return } if molecule == nil { - if let moleculeView = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeForJSON(json, delegateObject: delegateObject) { - addSubview(moleculeView) - NSLayoutConstraint.constraintPinSubview(toSuperview: moleculeView) + 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 + 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 } } diff --git a/MVMCoreUI/Molecules/MVMCoreUIMoleculeViewProtocol.h b/MVMCoreUI/Molecules/Protocols/MVMCoreUIMoleculeViewProtocol.h similarity index 79% rename from MVMCoreUI/Molecules/MVMCoreUIMoleculeViewProtocol.h rename to MVMCoreUI/Molecules/Protocols/MVMCoreUIMoleculeViewProtocol.h index cce08641..12557967 100644 --- a/MVMCoreUI/Molecules/MVMCoreUIMoleculeViewProtocol.h +++ b/MVMCoreUI/Molecules/Protocols/MVMCoreUIMoleculeViewProtocol.h @@ -22,6 +22,12 @@ // 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 diff --git a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.h b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.h index a79ca208..43a113c9 100644 --- a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.h +++ b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.h @@ -22,4 +22,7 @@ - (nullable UIView *)getMoleculeForName:(nonnull NSString *)name; - (nullable UIView *)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 *)getMoleculeForStackWithJSON:(nonnull NSDictionary *)json delegateObject:(nullable DelegateObject *)delegateObject; + @end diff --git a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m index f12179bc..9deb6cd5 100644 --- a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m +++ b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m @@ -45,20 +45,17 @@ - (nullable UIView *)getMoleculeForName:(nonnull NSString *)name { Class class = [self.moleculeMapping objectForKey:name]; - if (class) { - UIView *view = [[class alloc] init]; - if ([view respondsToSelector:@selector(needsToBeConstrained)] && [view needsToBeConstrained]) { - view = [[ViewConstrainingView alloc] initWithMolecule:view]; - } - if ([view respondsToSelector:@selector(setAsMolecule)]) { - [view setAsMolecule]; - } - return view; + if (!class) { + return nil; } - return nil; + UIView *molecule = [[class alloc] init]; + if ([molecule respondsToSelector:@selector(setAsMolecule)]) { + [molecule setAsMolecule]; + } + return molecule; } -- (nullable UIView *)getMoleculeForJSON:(nonnull NSDictionary *)json delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject { +- (nullable UIView *)getMoleculeForJSON:(nonnull NSDictionary *)json delegateObject:(nullable DelegateObject *)delegateObject { NSString *moleculeName = [json string:@"moleculeName"]; if (!moleculeName) { return nil; @@ -69,4 +66,17 @@ } +- (nullable UIView *)getMoleculeForStackWithJSON:(nonnull NSDictionary *)json delegateObject:(nullable DelegateObject *)delegateObject { + NSString *moleculeName = [json string:@"moleculeName"]; + if (!moleculeName) { + return nil; + } + UIView *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 diff --git a/MVMCoreUI/Templates/MoleculeListTemplate.swift b/MVMCoreUI/Templates/MoleculeListTemplate.swift index f1226056..ba6e7f15 100644 --- a/MVMCoreUI/Templates/MoleculeListTemplate.swift +++ b/MVMCoreUI/Templates/MoleculeListTemplate.swift @@ -23,14 +23,14 @@ public class MoleculeListTemplate: ThreeLayerTableViewController { } 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 super.viewForTop() } return molecule } 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 viewForBottom() } return molecule @@ -41,6 +41,14 @@ public class MoleculeListTemplate: ThreeLayerTableViewController { registerWithTable() } + public override func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat { + if let moleculeName = loadObject?.pageJSON?.stringOptionalWithChainOfKeysOrIndexes(["molecules",indexPath.row,"moleculeName"]), let theClass = MVMCoreUIMoleculeMappingObject.shared()?.moleculeMapping?[moleculeName] as? MVMCoreUIMoleculeViewProtocol.Type, + let estimatedHeightForRow = theClass.estimatedHeightForRow { + return estimatedHeightForRow() + } + return 0 + } + public override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return loadObject?.pageJSON?.arrayForKey("molecules").count ?? 0 } diff --git a/MVMCoreUI/Templates/MoleculeStackCenteredTemplate.swift b/MVMCoreUI/Templates/MoleculeStackCenteredTemplate.swift index bdd187fe..b359ecf5 100644 --- a/MVMCoreUI/Templates/MoleculeStackCenteredTemplate.swift +++ b/MVMCoreUI/Templates/MoleculeStackCenteredTemplate.swift @@ -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 diff --git a/MVMCoreUI/Templates/MoleculeStackTemplate.swift b/MVMCoreUI/Templates/MoleculeStackTemplate.swift index 8b3d652d..51b3ed7f 100644 --- a/MVMCoreUI/Templates/MoleculeStackTemplate.swift +++ b/MVMCoreUI/Templates/MoleculeStackTemplate.swift @@ -16,7 +16,7 @@ public class MoleculeStackTemplate: ThreeLayerViewController { } 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