clean up of stack
This commit is contained in:
parent
2221ab6672
commit
486cbfdc31
@ -21,6 +21,10 @@ public class StackItem {
|
|||||||
|
|
||||||
init(with view: UIView, json: [AnyHashable: Any]) {
|
init(with view: UIView, json: [AnyHashable: Any]) {
|
||||||
self.view = view
|
self.view = view
|
||||||
|
update(with: json)
|
||||||
|
}
|
||||||
|
|
||||||
|
func update(with json: [AnyHashable: Any]) {
|
||||||
spacing = json.optionalCGFloatForKey("spacing")
|
spacing = json.optionalCGFloatForKey("spacing")
|
||||||
percentage = json["percent"] as? Int
|
percentage = json["percent"] as? Int
|
||||||
if let alignment = json.optionalStringForKey("verticalAlignment") {
|
if let alignment = json.optionalStringForKey("verticalAlignment") {
|
||||||
@ -33,33 +37,29 @@ public class StackItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public class MoleculeStackView: ViewConstrainingView {
|
public class MoleculeStackView: ViewConstrainingView {
|
||||||
var spacingBlock: ((Any) -> UIEdgeInsets)?
|
|
||||||
var useMargins: Bool = false
|
|
||||||
|
|
||||||
var contentView: UIView = MVMCoreUICommonViewsUtility.commonView()
|
var contentView: UIView = MVMCoreUICommonViewsUtility.commonView()
|
||||||
var items: [StackItem] = []
|
var items: [StackItem] = []
|
||||||
|
|
||||||
private var spacingConstraints: [NSLayoutConstraint] = []
|
|
||||||
|
|
||||||
/// For setting the direction of the stack
|
/// For setting the direction of the stack
|
||||||
var axis: NSLayoutConstraint.Axis = .vertical {
|
var axis: NSLayoutConstraint.Axis = .vertical {
|
||||||
didSet {
|
didSet {
|
||||||
|
updateViewHorizontalDefaults = axis == .horizontal
|
||||||
if axis != oldValue {
|
if axis != oldValue {
|
||||||
restack()
|
restack()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The spacing to use between each item in the stack.
|
||||||
var spacing: CGFloat = 16 {
|
var spacing: CGFloat = 16 {
|
||||||
didSet {
|
didSet {
|
||||||
if spacing != oldValue {
|
if spacing != oldValue {
|
||||||
MVMCoreDispatchUtility.performBlock(onMainThread: {
|
restack()
|
||||||
// loop space bettwen constraints and update. skip custom ones...
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: - Helpers
|
||||||
public func setAxisWithJSON(_ json: [AnyHashable: Any]?) {
|
public func setAxisWithJSON(_ json: [AnyHashable: Any]?) {
|
||||||
switch json?.optionalStringForKey("axis") {
|
switch json?.optionalStringForKey("axis") {
|
||||||
case "horizontal":
|
case "horizontal":
|
||||||
@ -69,12 +69,20 @@ public class MoleculeStackView: ViewConstrainingView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func pinView(_ view: UIView, toView: UIView, attribute: NSLayoutConstraint.Attribute, relation: NSLayoutConstraint.Relation, priority: UILayoutPriority, constant: CGFloat) {
|
||||||
public func pinView(_ view: UIView, toView: UIView, attribute: NSLayoutConstraint.Attribute, relation: NSLayoutConstraint.Relation, priority: UILayoutPriority, constant: CGFloat) -> NSLayoutConstraint {
|
|
||||||
let constraint = NSLayoutConstraint(item: view, attribute: attribute, relatedBy: relation, toItem: toView, attribute: attribute, multiplier: 1.0, constant: constant)
|
let constraint = NSLayoutConstraint(item: view, attribute: attribute, relatedBy: relation, toItem: toView, attribute: attribute, multiplier: 1.0, constant: constant)
|
||||||
constraint.priority = priority
|
constraint.priority = priority
|
||||||
constraint.isActive = true
|
constraint.isActive = true
|
||||||
return constraint
|
}
|
||||||
|
|
||||||
|
/// Restacks the existing items.
|
||||||
|
func restack() {
|
||||||
|
MVMCoreUIStackableViewController.remove(contentView.subviews)
|
||||||
|
let stackItems = items
|
||||||
|
items.removeAll()
|
||||||
|
for (index, item) in stackItems.enumerated() {
|
||||||
|
addStackItem(item, lastItem: index == stackItems.count - 1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Inits
|
// MARK: - Inits
|
||||||
@ -87,11 +95,6 @@ public class MoleculeStackView: ViewConstrainingView {
|
|||||||
setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
|
setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
|
||||||
}
|
}
|
||||||
|
|
||||||
public convenience init(withJSON json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, spacingBlock: ((Any) -> UIEdgeInsets)?) {
|
|
||||||
self.init(withJSON: json, delegateObject: delegateObject, additionalData: nil)
|
|
||||||
self.spacingBlock = spacingBlock
|
|
||||||
}
|
|
||||||
|
|
||||||
public required init?(coder aDecoder: NSCoder) {
|
public required init?(coder aDecoder: NSCoder) {
|
||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
@ -111,15 +114,18 @@ public class MoleculeStackView: ViewConstrainingView {
|
|||||||
|
|
||||||
public override func updateView(_ size: CGFloat) {
|
public override func updateView(_ size: CGFloat) {
|
||||||
super.updateView(size)
|
super.updateView(size)
|
||||||
for view in subviews {
|
for item in items {
|
||||||
if let mvmView = view as? MVMCoreViewProtocol {
|
(item.view as? MVMCoreViewProtocol)?.updateView(size)
|
||||||
mvmView.updateView(size)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - MVMCoreUIMoleculeViewProtocol
|
// MARK: - MVMCoreUIMoleculeViewProtocol
|
||||||
|
public override func setAsMolecule() {
|
||||||
|
updateViewHorizontalDefaults = false
|
||||||
|
}
|
||||||
|
|
||||||
public override func reset() {
|
public override func reset() {
|
||||||
|
backgroundColor = .clear
|
||||||
for item in items {
|
for item in items {
|
||||||
if let view = item.view as? MVMCoreUIMoleculeViewProtocol {
|
if let view = item.view as? MVMCoreUIMoleculeViewProtocol {
|
||||||
view.reset?()
|
view.reset?()
|
||||||
@ -128,9 +134,21 @@ public class MoleculeStackView: ViewConstrainingView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
|
open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
|
||||||
|
let previousJSON = self.json
|
||||||
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
|
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
|
||||||
clear()
|
MVMCoreUIStackableViewController.remove(contentView.subviews)
|
||||||
|
|
||||||
|
// If the items in the stack are the same, just update previous items instead of re-allocating.
|
||||||
|
var items: [StackItem]?
|
||||||
|
if MoleculeStackView.name(forReuse: previousJSON, delegateObject: delegateObject) == MoleculeStackView.name(forReuse: json, delegateObject: delegateObject) {
|
||||||
|
items = self.items
|
||||||
|
}
|
||||||
|
self.items = []
|
||||||
|
|
||||||
|
if let colorString = json?.optionalStringForKey(KeyBackgroundColor) {
|
||||||
|
backgroundColor = .mfGet(forHex: colorString)
|
||||||
|
}
|
||||||
|
|
||||||
guard let molecules = json?.arrayForKey(KeyMolecules) as? [[String: Any]] else {
|
guard let molecules = json?.arrayForKey(KeyMolecules) as? [[String: Any]] else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -148,59 +166,28 @@ public class MoleculeStackView: ViewConstrainingView {
|
|||||||
alignVertical(.leading)
|
alignVertical(.leading)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the molecules and set the json.
|
// Adds the molecules and sets the json.
|
||||||
for (index, map) in molecules.enumerated() {
|
for (index, map) in molecules.enumerated() {
|
||||||
if let moleculeJSON = map.optionalDictionaryForKey(KeyMolecule), let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject, constrainIfNeeded: true) {
|
if let moleculeJSON = map.optionalDictionaryForKey(KeyMolecule) {
|
||||||
|
var view: UIView?
|
||||||
addStackItem(StackItem(with: molecule, json: map), lastItem: index == molecules.count - 1)
|
if let item = items?[index] {
|
||||||
/*contentView.addSubview(molecule)
|
(item.view as? MVMCoreUIMoleculeViewProtocol)?.setWithJSON(moleculeJSON, delegateObject: delegateObject, additionalData: additionalData)
|
||||||
molecule.translatesAutoresizingMaskIntoConstraints = false
|
item.update(with: moleculeJSON)
|
||||||
|
view = item.view
|
||||||
let spacing = CGFloat(map["spacing"] as? Float ?? self.spacing)
|
addStackItem(item, lastItem: index == molecules.count - 1)
|
||||||
let percent = map["percent"] as? Int
|
} else if let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject, constrainIfNeeded: true) {
|
||||||
let verticalAlignment = ViewConstrainingView.getAlignmentFor(map.optionalStringForKey("verticalAlignment"), defaultAlignment: (percent == nil && axis == .vertical ? UIStackView.Alignment.fill : UIStackView.Alignment.leading))
|
view = molecule
|
||||||
let horizontalAlignment = ViewConstrainingView.getAlignmentFor(map.optionalStringForKey("horizontalAlignment"), defaultAlignment: (axis == .vertical || percent == nil ? UIStackView.Alignment.fill : UIStackView.Alignment.leading))
|
addStackItem(StackItem(with: molecule, json: map), lastItem: index == molecules.count - 1)
|
||||||
|
|
||||||
if let molecule = molecule as? MVMCoreUIViewConstrainingProtocol {
|
|
||||||
molecule.alignHorizontal?(horizontalAlignment)
|
|
||||||
molecule.alignVertical?(verticalAlignment)
|
|
||||||
}
|
}
|
||||||
if axis == .vertical {
|
|
||||||
if index == 0 {
|
(view as? MVMCoreUIViewConstrainingProtocol)?.shouldSetHorizontalMargins?(axis == .vertical)
|
||||||
pinView(molecule, toView: previousObject, attribute: .top, relation: .equal, priority: .required, constant: spacing)
|
(view as? MVMCoreUIViewConstrainingProtocol)?.shouldSetVerticalMargins?(false)
|
||||||
} else {
|
|
||||||
NSLayoutConstraint(pinFirstView: previousObject, toSecondView: molecule, withConstant: spacing, directionVertical: true)?.isActive = true
|
|
||||||
}
|
|
||||||
pinView(molecule, toView: contentView, attribute: .leading, relation: .equal, priority: .required, constant: 0)
|
|
||||||
pinView(contentView, toView: molecule, attribute: .trailing, relation: .equal, priority: .required, constant: 0)
|
|
||||||
if let percent = percent {
|
|
||||||
molecule.heightAnchor.constraint(equalTo: contentView.heightAnchor, multiplier: CGFloat(percent)/100.0).isActive = true
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if index == 0 {
|
|
||||||
pinView(molecule, toView: previousObject, attribute: .leading, relation: .equal, priority: .required, constant: spacing)
|
|
||||||
} else {
|
|
||||||
NSLayoutConstraint(pinFirstView: previousObject, toSecondView: molecule, withConstant: spacing, directionVertical: false)?.isActive = true
|
|
||||||
}
|
|
||||||
pinView(molecule, toView: contentView, attribute: .top, relation: .equal, priority: .required, constant: 0)
|
|
||||||
pinView(contentView, toView: molecule, attribute: .bottom, relation: .equal, priority: .required, constant: 0)
|
|
||||||
if let percent = percent {
|
|
||||||
molecule.widthAnchor.constraint(equalTo: contentView.widthAnchor, multiplier: CGFloat(percent)/100.0).isActive = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
previousObject = molecule
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if axis == .vertical {
|
|
||||||
pinView(contentView, toView: previousObject, attribute: .bottom, relation: .equal, priority: .required, constant: 0)
|
|
||||||
} else {
|
|
||||||
pinView(contentView, toView: previousObject, attribute: .right, relation: .equal, priority: .required, constant: 0)
|
|
||||||
}*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override static func name(forReuse molecule: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> String? {
|
public override static func name(forReuse molecule: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> String? {
|
||||||
|
// This will aggregate names of molecules to make an id.
|
||||||
var name = ""
|
var name = ""
|
||||||
guard let molecules = molecule?.optionalArrayForKey(KeyMolecules) else {
|
guard let molecules = molecule?.optionalArrayForKey(KeyMolecules) else {
|
||||||
return name
|
return name
|
||||||
@ -213,21 +200,7 @@ public class MoleculeStackView: ViewConstrainingView {
|
|||||||
return name
|
return name
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Convenience Functions
|
// MARK: - Adding to stack
|
||||||
func clear() {
|
|
||||||
MVMCoreUIStackableViewController.remove(contentView.subviews)
|
|
||||||
spacingConstraints = []
|
|
||||||
}
|
|
||||||
|
|
||||||
func restack() {
|
|
||||||
clear()
|
|
||||||
let stackItems = items
|
|
||||||
items.removeAll()
|
|
||||||
for (index, item) in stackItems.enumerated() {
|
|
||||||
addStackItem(item, lastItem: index == stackItems.count - 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Adds the view to the stack.
|
/// Adds the view to the stack.
|
||||||
func addView(_ view: UIView, lastItem: Bool) {
|
func addView(_ view: UIView, lastItem: Bool) {
|
||||||
addStackItem(StackItem(with: view), lastItem: lastItem)
|
addStackItem(StackItem(with: view), lastItem: lastItem)
|
||||||
@ -248,9 +221,9 @@ public class MoleculeStackView: ViewConstrainingView {
|
|||||||
}
|
}
|
||||||
if axis == .vertical {
|
if axis == .vertical {
|
||||||
if items.count == 0 {
|
if items.count == 0 {
|
||||||
spacingConstraints.append(pinView(view, toView: contentView, attribute: .top, relation: .equal, priority: .required, constant: spacing))
|
pinView(view, toView: contentView, attribute: .top, relation: .equal, priority: .required, constant: spacing)
|
||||||
} else if let previousView = items.last?.view {
|
} else if let previousView = items.last?.view {
|
||||||
spacingConstraints.append(NSLayoutConstraint(pinFirstView: previousView, toSecondView: view, withConstant: spacing, directionVertical: true))
|
_ = NSLayoutConstraint(pinFirstView: previousView, toSecondView: view, withConstant: spacing, directionVertical: true)
|
||||||
}
|
}
|
||||||
pinView(view, toView: contentView, attribute: .leading, relation: .equal, priority: .required, constant: 0)
|
pinView(view, toView: contentView, attribute: .leading, relation: .equal, priority: .required, constant: 0)
|
||||||
pinView(contentView, toView: view, attribute: .trailing, relation: .equal, priority: .required, constant: 0)
|
pinView(contentView, toView: view, attribute: .trailing, relation: .equal, priority: .required, constant: 0)
|
||||||
@ -263,9 +236,9 @@ public class MoleculeStackView: ViewConstrainingView {
|
|||||||
} else {
|
} else {
|
||||||
if items.count == 0 {
|
if items.count == 0 {
|
||||||
// First horizontal item has no spacing by default unless told otherwise.
|
// First horizontal item has no spacing by default unless told otherwise.
|
||||||
spacingConstraints.append(pinView(view, toView: contentView, attribute: .leading, relation: .equal, priority: .required, constant: stackItem.spacing ?? 0))
|
pinView(view, toView: contentView, attribute: .leading, relation: .equal, priority: .required, constant: stackItem.spacing ?? 0)
|
||||||
} else if let previousView = items.last?.view {
|
} else if let previousView = items.last?.view {
|
||||||
spacingConstraints.append(NSLayoutConstraint(pinFirstView: previousView, toSecondView: view, withConstant: spacing, directionVertical: false))
|
_ = NSLayoutConstraint(pinFirstView: previousView, toSecondView: view, withConstant: spacing, directionVertical: false)
|
||||||
}
|
}
|
||||||
pinView(view, toView: contentView, attribute: .top, relation: .equal, priority: .required, constant: 0)
|
pinView(view, toView: contentView, attribute: .top, relation: .equal, priority: .required, constant: 0)
|
||||||
pinView(contentView, toView: view, attribute: .bottom, relation: .equal, priority: .required, constant: 0)
|
pinView(contentView, toView: view, attribute: .bottom, relation: .equal, priority: .required, constant: 0)
|
||||||
|
|||||||
@ -44,6 +44,7 @@ import UIKit
|
|||||||
MFStyler.setDefaultMarginsFor(self, size: size, horizontal: true, vertical: true)
|
MFStyler.setDefaultMarginsFor(self, size: size, horizontal: true, vertical: true)
|
||||||
if #available(iOS 11.0, *) {
|
if #available(iOS 11.0, *) {
|
||||||
if accessoryView != nil {
|
if accessoryView != nil {
|
||||||
|
// Smaller left margin if accessory view.
|
||||||
var margin = directionalLayoutMargins
|
var margin = directionalLayoutMargins
|
||||||
margin.trailing = 16
|
margin.trailing = 16
|
||||||
contentView.directionalLayoutMargins = margin
|
contentView.directionalLayoutMargins = margin
|
||||||
@ -54,6 +55,7 @@ import UIKit
|
|||||||
bottomSeparatorView?.setLeftAndRightPinConstant(directionalLayoutMargins.leading)
|
bottomSeparatorView?.setLeftAndRightPinConstant(directionalLayoutMargins.leading)
|
||||||
} else {
|
} else {
|
||||||
if accessoryView != nil {
|
if accessoryView != nil {
|
||||||
|
// Smaller left margin if accessory view.
|
||||||
var margin = layoutMargins
|
var margin = layoutMargins
|
||||||
margin.right = 16
|
margin.right = 16
|
||||||
contentView.layoutMargins = margin
|
contentView.layoutMargins = margin
|
||||||
@ -87,15 +89,17 @@ import UIKit
|
|||||||
if molecule == nil {
|
if molecule == nil {
|
||||||
if let moleculeView = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject, constrainIfNeeded: true) {
|
if let moleculeView = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject, constrainIfNeeded: true) {
|
||||||
contentView.addSubview(moleculeView)
|
contentView.addSubview(moleculeView)
|
||||||
let standardConstraints = (moleculeView as? MVMCoreUIViewConstrainingProtocol)?.useStandardConstraints?() ?? true
|
var standardConstraints = true
|
||||||
|
if let castView = moleculeView as? MVMCoreUIViewConstrainingProtocol {
|
||||||
|
standardConstraints = castView.useStandardConstraints?() ?? true
|
||||||
|
castView.shouldSetHorizontalMargins?(!standardConstraints)
|
||||||
|
castView.shouldSetVerticalMargins?(!standardConstraints)
|
||||||
|
}
|
||||||
NSLayoutConstraint.activate(Array(NSLayoutConstraint.pinView(toSuperview: moleculeView, useMargins: standardConstraints).values))
|
NSLayoutConstraint.activate(Array(NSLayoutConstraint.pinView(toSuperview: moleculeView, useMargins: standardConstraints).values))
|
||||||
if standardConstraints {
|
if standardConstraints {
|
||||||
let constraint = contentView.heightAnchor.constraint(equalToConstant: 80)
|
let constraint = contentView.heightAnchor.constraint(equalToConstant: 80)
|
||||||
constraint.priority = .defaultLow
|
constraint.priority = .defaultLow
|
||||||
constraint.isActive = true
|
constraint.isActive = true
|
||||||
if let moleculeView = moleculeView as? ViewConstrainingView {
|
|
||||||
moleculeView.updateViewHorizontalDefaults = false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
molecule = moleculeView
|
molecule = moleculeView
|
||||||
}
|
}
|
||||||
@ -126,7 +130,7 @@ import UIKit
|
|||||||
guard let moleculeJSON = json?.optionalDictionaryForKey(KeyMolecule),
|
guard let moleculeJSON = json?.optionalDictionaryForKey(KeyMolecule),
|
||||||
let theClass = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: moleculeJSON, delegateObject: nil),
|
let theClass = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: moleculeJSON, delegateObject: nil),
|
||||||
let estimatedHeightFor = theClass.estimatedHeight else {
|
let estimatedHeightFor = theClass.estimatedHeight else {
|
||||||
return 0
|
return 80
|
||||||
}
|
}
|
||||||
return estimatedHeightFor(moleculeJSON)
|
return estimatedHeightFor(moleculeJSON)
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user