stack item as container

This commit is contained in:
Pfeil, Scott Robert 2019-12-13 17:07:10 -05:00
parent be1b867a9a
commit 7f01bc286c
8 changed files with 137 additions and 84 deletions

View File

@ -199,6 +199,7 @@
D2E1FADF2268B8E700AEFD8C /* ThreeLayerTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2E1FADE2268B8E700AEFD8C /* ThreeLayerTableViewController.swift */; };
D2E1FAE12268E81D00AEFD8C /* MoleculeListTemplate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2E1FAE02268E81D00AEFD8C /* MoleculeListTemplate.swift */; };
D2FB151B23A2B65B00C20E10 /* MoleculeContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2FB151A23A2B65B00C20E10 /* MoleculeContainer.swift */; };
D2FB151D23A40F1500C20E10 /* StackItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2FB151C23A40F1500C20E10 /* StackItem.swift */; };
DB06250B2293456500B72DD3 /* LeftRightLabelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB06250A2293456500B72DD3 /* LeftRightLabelView.swift */; };
DBC4391822442197001AB423 /* CaretView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBC4391622442196001AB423 /* CaretView.swift */; };
DBC4391922442197001AB423 /* DashLine.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBC4391722442197001AB423 /* DashLine.swift */; };
@ -404,6 +405,7 @@
D2E1FAE02268E81D00AEFD8C /* MoleculeListTemplate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeListTemplate.swift; sourceTree = "<group>"; };
D2F4DDE52371A4CB00CD28BB /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
D2FB151A23A2B65B00C20E10 /* MoleculeContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeContainer.swift; sourceTree = "<group>"; };
D2FB151C23A40F1500C20E10 /* StackItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StackItem.swift; sourceTree = "<group>"; };
DB06250A2293456500B72DD3 /* LeftRightLabelView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LeftRightLabelView.swift; sourceTree = "<group>"; };
DB891E822253FA8500022516 /* Label.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Label.swift; sourceTree = "<group>"; };
DBC4391622442196001AB423 /* CaretView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CaretView.swift; sourceTree = "<group>"; };
@ -524,6 +526,7 @@
D224799A231965AD003FCCF9 /* AccordionMoleculeTableViewCell.swift */,
D27CD40D2322EEAF00C1DC07 /* TabsTableViewCell.swift */,
D268C70D238C22D7007F2C1C /* DropDownFilterTableViewCell.swift */,
D2FB151C23A40F1500C20E10 /* StackItem.swift */,
);
path = Items;
sourceTree = "<group>";
@ -1076,6 +1079,7 @@
D29B771022C281F400D6ACE0 /* ModuleMolecule.swift in Sources */,
DBC4391922442197001AB423 /* DashLine.swift in Sources */,
0A7BAD74232A8DC700FB8E22 /* HeadlineBodyButton.swift in Sources */,
D2FB151D23A40F1500C20E10 /* StackItem.swift in Sources */,
D29DF29621E7ADB8003B2FB9 /* StackableViewController.m in Sources */,
0116A4E5228B19640094F3ED /* RadioButtonModel.swift in Sources */,
D2E1FADB2260D3D200AEFD8C /* MVMCoreUIDelegateObject.swift in Sources */,

View File

@ -9,10 +9,10 @@
import UIKit
public protocol ContainerModelProtocol {
var horizontalAlignment: UIStackView.Alignment { get set }
var verticalAlignment: UIStackView.Alignment { get set }
var useHorizontalMargins: Bool { get set }
var useVerticalMargins: Bool { get set }
var horizontalAlignment: UIStackView.Alignment? { get set }
var verticalAlignment: UIStackView.Alignment? { get set }
var useHorizontalMargins: Bool? { get set }
var useVerticalMargins: Bool? { get set }
}
public class ContainerHelper: NSObject {
@ -146,8 +146,12 @@ public class ContainerHelper: NSObject {
}
func set(with model: ContainerModelProtocol) {
alignHorizontal(model.horizontalAlignment)
alignVertical(model.verticalAlignment)
if let horizontalAlignment = model.horizontalAlignment {
alignHorizontal(horizontalAlignment)
}
if let verticalAlignment = model.verticalAlignment {
alignVertical(verticalAlignment)
}
}
static func getAlignment(for string: String) -> UIStackView.Alignment? {
@ -188,6 +192,17 @@ public extension Container {
super.setupView()
backgroundColor = .clear
}
func addAndContain(_ view: UIView) {
addSubview(view)
containerHelper.constrainView(view)
self.view = view
}
convenience init(andContain view: UIView) {
self.init()
addAndContain(view)
}
}
// MARK: - MVMCoreUIMoleculeViewProtocol
@ -207,4 +222,9 @@ public extension Container {
containerHelper.alignVertical(alignment)
}
}
override func reset() {
super.reset()
(view as? MVMCoreUIMoleculeViewProtocol)?.reset?()
}
}

View File

@ -0,0 +1,56 @@
//
// StackItem.swift
// MVMCoreUI
//
// Created by Scott Pfeil on 12/13/19.
// Copyright © 2019 Verizon Wireless. All rights reserved.
//
import UIKit
open class StackItemModel: ContainerModelProtocol {
public var view: StackItem
public var spacing: CGFloat?
public var percentage: Int?
public var verticalAlignment: UIStackView.Alignment?
public var horizontalAlignment: UIStackView.Alignment?
public var useHorizontalMargins: Bool?
public var useVerticalMargins: Bool?
public var gone = false
init(with view: StackItem) {
self.view = view
view.model = self
}
init(with view: StackItem, json: [AnyHashable: Any]?) {
self.view = view
view.model = self
update(with: json)
}
func update(with json: [AnyHashable: Any]?) {
gone = json?.boolForKey("gone") ?? (json == nil)
spacing = json?.optionalCGFloatForKey("spacing")
percentage = json?["percent"] as? Int
if let horizontalAlignmentString = json?.optionalStringForKey("horizontalAlignment") {
horizontalAlignment = ContainerHelper.getAlignment(for: horizontalAlignmentString)
} else {
horizontalAlignment = nil
}
if let verticalAlignmentString = json?.optionalStringForKey("verticalAlignment") {
verticalAlignment = ContainerHelper.getAlignment(for: verticalAlignmentString)
} else {
verticalAlignment = nil
}
useHorizontalMargins = json?.optionalBoolForKey("useHorizontalMargins") ?? false
useVerticalMargins = json?.optionalBoolForKey("useVerticalMargins") ?? false
}
}
open class StackItem: MoleculeContainer {
}

View File

@ -17,18 +17,11 @@ open class MoleculeContainer: Container {
}
if view == nil {
if let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject, constrainIfNeeded: false) {
addSubview(molecule)
containerHelper.constrainView(molecule)
view = molecule
addAndContain(molecule)
}
} else {
(view as? MVMCoreUIMoleculeViewProtocol)?.setWithJSON(moleculeJSON, delegateObject: delegateObject, additionalData: additionalData)
}
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
}
open override func reset() {
super.reset()
(view as? MVMCoreUIMoleculeViewProtocol)?.reset?()
}
}

View File

@ -21,4 +21,10 @@ open class StandardFooterView: MoleculeContainer {
}
return 42
}
open override func reset() {
super.reset()
topMarginPadding = PaddingDefaultVerticalSpacing
bottomMarginPadding = PaddingDefaultVerticalSpacing
}
}

View File

@ -22,15 +22,14 @@ import UIKit
return
}
stack.spacing = 0
stack.updateViewHorizontalDefaults = false
addSubview(stack)
pinView(toSuperView: stack)
stack.addStackItem(StackItem(with: eyebrow), lastItem: false)
stack.addStackItem(StackItem(with: headline), lastItem: false)
stack.addStackItem(StackItem(with: body), lastItem: false)
stack.addStackItem(StackItemModel(with: StackItem(andContain: eyebrow)), lastItem: false)
stack.addStackItem(StackItemModel(with: StackItem(andContain: headline)), lastItem: false)
stack.addStackItem(StackItemModel(with: StackItem(andContain: body)), lastItem: false)
// To visually take into account the extra padding in the intrinsic content of a button.
let stackItem = StackItem(with: link)
let stackItem = StackItemModel(with: StackItem(andContain: link))
stackItem.spacing = -6
stack.addStackItem(stackItem, lastItem: true)
}
@ -38,6 +37,8 @@ import UIKit
open override func updateView(_ size: CGFloat) {
super.updateView(size)
stack.updateView(size)
stack.directionalLayoutMargins.leading = 0
stack.directionalLayoutMargins.trailing = 0
}
// MARK: - MVMCoreUIMoleculeViewProtocol
@ -58,7 +59,6 @@ import UIKit
super.reset()
stack.reset()
stack.spacing = 0
stack.updateViewHorizontalDefaults = false
eyebrow.styleB3(true)
headline.styleB1(true)
body.styleB2(true)

View File

@ -8,47 +8,13 @@
import UIKit
public class StackItem {
var view: UIView
var spacing: CGFloat?
var percentage: Int?
var verticalAlignment: UIStackView.Alignment?
var horizontalAlignment: UIStackView.Alignment?
var gone = false
init(with view: UIView) {
self.view = view
}
init(with view: UIView, json: [AnyHashable: Any]?) {
self.view = view
update(with: json)
}
func update(with json: [AnyHashable: Any]?) {
gone = json?.boolForKey("gone") ?? (json == nil)
spacing = json?.optionalCGFloatForKey("spacing")
percentage = json?["percent"] as? Int
if let alignment = json?.stringOptionalWithChainOfKeysOrIndexes([KeyMolecule,"verticalAlignment"]) {
verticalAlignment = ViewConstrainingView.getAlignmentFor(alignment, defaultAlignment: .fill)
} else {
verticalAlignment = nil
}
if let alignment = json?.stringOptionalWithChainOfKeysOrIndexes([KeyMolecule,"horizontalAlignment"]) {
horizontalAlignment = ViewConstrainingView.getAlignmentFor(alignment, defaultAlignment: .fill)
} else {
horizontalAlignment = nil
}
}
}
public class MoleculeStackView: ViewConstrainingView {
open class MoleculeStackView: Container {
var contentView: UIView = MVMCoreUICommonViewsUtility.commonView()
var items: [StackItem] = []
var items: [StackItemModel] = []
var useStackSpacingBeforeFirstItem = false
private var moleculesShouldSetHorizontalMargins = false
private var moleculesShouldSetVerticalMargins = false
var moleculesShouldSetHorizontalMargins = false
var moleculesShouldSetVerticalMargins = false
/// For setting the direction of the stack
var axis: NSLayoutConstraint.Axis = .vertical {
@ -97,6 +63,10 @@ public class MoleculeStackView: ViewConstrainingView {
}
// MARK: - Inits
public override init() {
super.init()
}
public override init(frame: CGRect) {
super.init(frame: frame)
}
@ -117,19 +87,20 @@ public class MoleculeStackView: ViewConstrainingView {
return
}
MVMCoreUIUtility.setMarginsFor(contentView, leading: 0, top: 0, trailing: 0, bottom: 0)
updateViewHorizontalDefaults = true
translatesAutoresizingMaskIntoConstraints = false
backgroundColor = .clear
addSubview(contentView)
pinView(toSuperView: contentView)
containerHelper.constrainView(contentView)
contentView.setContentHuggingPriority(.defaultHigh, for: .vertical)
contentView.setContentHuggingPriority(.defaultHigh, for: .horizontal)
}
public override func updateView(_ size: CGFloat) {
super.updateView(size)
directionalLayoutMargins.leading = 0
directionalLayoutMargins.trailing = 0
for item in items {
(item.view as? MVMCoreViewProtocol)?.updateView(size)
item.view.updateView(size)
}
}
@ -137,11 +108,8 @@ public class MoleculeStackView: ViewConstrainingView {
public override func reset() {
super.reset()
backgroundColor = .clear
updateViewHorizontalDefaults = true
for item in items {
if let view = item.view as? MVMCoreUIMoleculeViewProtocol {
view.reset?()
}
item.view.reset()
}
}
@ -151,7 +119,7 @@ public class MoleculeStackView: ViewConstrainingView {
removeAllItemViews()
// If the items in the stack are the same, just update previous items instead of re-allocating.
var items: [StackItem]?
var items: [StackItemModel]?
if MoleculeStackView.name(forReuse: previousJSON, delegateObject: delegateObject) == MoleculeStackView.name(forReuse: json, delegateObject: delegateObject) {
items = self.items
}
@ -169,22 +137,28 @@ public class MoleculeStackView: ViewConstrainingView {
for (index, map) in molecules.enumerated() {
if let moleculeJSON = map.optionalDictionaryForKey(KeyMolecule) {
var view: UIView?
var stackItemModel: StackItemModel
if let item = items?[index] {
stackItemModel = item
item.update(with: map)
view = item.view
(view as? MVMCoreUIMoleculeViewProtocol)?.setWithJSON(moleculeJSON, delegateObject: delegateObject, additionalData: nil)
addStackItem(item, lastItem: index == molecules.count - 1)
} else if let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject, constrainIfNeeded: true) {
view = molecule
addStackItem(StackItem(with: molecule, json: map), lastItem: index == molecules.count - 1)
} else {
let stackItem = StackItem()
stackItem.setWithJSON(map, delegateObject: delegateObject, additionalData: additionalData)
view = stackItem
stackItemModel = StackItemModel(with: stackItem, json: map)
addStackItem(stackItemModel, lastItem: index == molecules.count - 1)
}
(view as? MVMCoreUIViewConstrainingProtocol)?.shouldSetHorizontalMargins?(moleculesShouldSetHorizontalMargins)
(view as? MVMCoreUIViewConstrainingProtocol)?.shouldSetVerticalMargins?(moleculesShouldSetVerticalMargins)
stackItemModel.useHorizontalMargins = moleculesShouldSetHorizontalMargins
stackItemModel.useVerticalMargins = moleculesShouldSetVerticalMargins
}
}
}
public override class func name(forReuse molecule: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> String? {
public class func name(forReuse molecule: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> String? {
// This will aggregate names of molecules to make an id.
guard let molecules = molecule?.optionalArrayForKey(KeyMolecules) else {
return "stack<>"
@ -199,7 +173,7 @@ public class MoleculeStackView: ViewConstrainingView {
return name
}
public override class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
public class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
guard let items = json?.optionalArrayForKey(KeyMolecules) else {
return 0
}
@ -221,7 +195,7 @@ public class MoleculeStackView: ViewConstrainingView {
return estimatedHeight
}
public override class func requiredModules(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer<MVMCoreErrorObject?>?) -> [String]? {
public class func requiredModules(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer<MVMCoreErrorObject?>?) -> [String]? {
guard let items = json?.optionalArrayForKey(KeyMolecules) else {
return nil
}
@ -237,11 +211,11 @@ public class MoleculeStackView: ViewConstrainingView {
// MARK: - Adding to stack
/// Adds the view to the stack.
func addView(_ view: UIView, lastItem: Bool) {
addStackItem(StackItem(with: view), lastItem: lastItem)
addStackItem(StackItemModel(with: StackItem(andContain: view)), lastItem: lastItem)
}
/// Adds the stack item to the stack.
func addStackItem(_ stackItem: StackItem, lastItem: Bool) {
func addStackItem(_ stackItem: StackItemModel, lastItem: Bool) {
guard !stackItem.gone else {
items.append(stackItem)
return
@ -251,12 +225,11 @@ public class MoleculeStackView: ViewConstrainingView {
view.translatesAutoresizingMaskIntoConstraints = false
let spacing = stackItem.spacing ?? self.spacing
if let view = view as? MVMCoreUIViewConstrainingProtocol {
let verticalAlignment = stackItem.verticalAlignment ?? (stackItem.percentage == nil && axis == .vertical ? .fill : (axis == .vertical ? .leading : .center))
let horizontalAlignment = stackItem.horizontalAlignment ?? view.alignment?() ?? (axis == .vertical || stackItem.percentage == nil ? .fill : .leading)
view.alignHorizontal?(horizontalAlignment)
view.alignVertical?(verticalAlignment)
}
let verticalAlignment = stackItem.verticalAlignment ?? (stackItem.percentage == nil && axis == .vertical ? .fill : (axis == .vertical ? .leading : .center))
let horizontalAlignment = stackItem.horizontalAlignment ?? (view.view as? MVMCoreUIViewConstrainingProtocol)?.horizontalAlignment?() ?? (axis == .vertical || stackItem.percentage == nil ? .fill : .leading)
view.containerHelper.alignHorizontal(horizontalAlignment)
view.containerHelper.alignVertical(verticalAlignment)
let first = items.first { !$0.gone } == nil
if axis == .vertical {
if first {
@ -295,10 +268,10 @@ public class MoleculeStackView: ViewConstrainingView {
items.append(stackItem)
}
func setWithStackItems(_ items: [StackItem]) {
func setWithStackItems(_ items: [StackItemModel]) {
removeAllItemViews()
self.items.removeAll()
var previousPresentItem: StackItem? = nil
var previousPresentItem: StackItemModel? = nil
for item in items {
if !item.gone {
previousPresentItem = item

View File

@ -42,6 +42,7 @@ open class MoleculeStackTemplate: ThreeLayerViewController {
}
let stack = MoleculeStackView(frame: .zero)
stack.useStackSpacingBeforeFirstItem = true
stack.moleculesShouldSetHorizontalMargins = true
stack.setWithJSON(moleculeJSON, delegateObject: delegateObject() as? MVMCoreUIDelegateObject, additionalData: nil)
return stack
}