threelayer base. Anchored header footer for non table

This commit is contained in:
Pfeil, Scott Robert 2020-04-21 18:40:23 -04:00
parent 565c01148c
commit a697fea926
11 changed files with 128 additions and 58 deletions

View File

@ -238,6 +238,8 @@
D209234F244F77FD0044AD09 /* ThreeLayerCenterTemplate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D209234E244F77FD0044AD09 /* ThreeLayerCenterTemplate.swift */; };
D2092351244F7BE80044AD09 /* ThreeLayerCenterTemplateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2092350244F7BE80044AD09 /* ThreeLayerCenterTemplateModel.swift */; };
D2092353244F7D630044AD09 /* MVMCoreUIViewControllerMappingObject+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2092352244F7D630044AD09 /* MVMCoreUIViewControllerMappingObject+Extension.swift */; };
D2092355244FA0FD0044AD09 /* ThreeLayerTemplateModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2092354244FA0FD0044AD09 /* ThreeLayerTemplateModelProtocol.swift */; };
D2092357244FA1EF0044AD09 /* ThreeLayerModelBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2092356244FA1EF0044AD09 /* ThreeLayerModelBase.swift */; };
D20A9A5E2243D3E300ADE781 /* TwoButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20A9A5D2243D3E300ADE781 /* TwoButtonView.swift */; };
D20FB165241A5D75004AFC3A /* NavigationItemModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20FB164241A5D75004AFC3A /* NavigationItemModelProtocol.swift */; };
D213347723843825008E41B3 /* Line.swift in Sources */ = {isa = PBXBuildFile; fileRef = D213347623843825008E41B3 /* Line.swift */; };
@ -680,6 +682,8 @@
D209234E244F77FD0044AD09 /* ThreeLayerCenterTemplate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreeLayerCenterTemplate.swift; sourceTree = "<group>"; };
D2092350244F7BE80044AD09 /* ThreeLayerCenterTemplateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreeLayerCenterTemplateModel.swift; sourceTree = "<group>"; };
D2092352244F7D630044AD09 /* MVMCoreUIViewControllerMappingObject+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MVMCoreUIViewControllerMappingObject+Extension.swift"; sourceTree = "<group>"; };
D2092354244FA0FD0044AD09 /* ThreeLayerTemplateModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreeLayerTemplateModelProtocol.swift; sourceTree = "<group>"; };
D2092356244FA1EF0044AD09 /* ThreeLayerModelBase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreeLayerModelBase.swift; sourceTree = "<group>"; };
D20A9A5D2243D3E300ADE781 /* TwoButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TwoButtonView.swift; sourceTree = "<group>"; };
D20FB164241A5D75004AFC3A /* NavigationItemModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationItemModelProtocol.swift; sourceTree = "<group>"; };
D213347623843825008E41B3 /* Line.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Line.swift; sourceTree = "<group>"; };
@ -938,6 +942,7 @@
D28A837823C7D5BC00DFE4FC /* PageModelProtocol.swift */,
011B58EF23A2AA980085F53C /* ListItemModelProtocol.swift */,
D2E2A9A223E096B1000B42E6 /* DisableableModelProtocol.swift */,
D2092354244FA0FD0044AD09 /* ThreeLayerTemplateModelProtocol.swift */,
);
path = ModelProtocols;
sourceTree = "<group>";
@ -1523,6 +1528,7 @@
isa = PBXGroup;
children = (
D22D8392241C27B100D3DF69 /* TemplateModel.swift */,
D2092356244FA1EF0044AD09 /* ThreeLayerModelBase.swift */,
014AA72823C5059B006F3E93 /* StackPageTemplateModel.swift */,
D2A5146022121FBF00345BFB /* MoleculeStackTemplate.swift */,
942C378D2412F5B60066E45E /* ModalMoleculeStackTemplate.swift */,
@ -2236,6 +2242,7 @@
0A7EF85B23D8A52800B2AAD1 /* EntryFieldModel.swift in Sources */,
8DEFA95C243DAC20000D27E5 /* ListThreeColumnDataUsageDividerModel.swift in Sources */,
94F217B723E0BF6100A47C06 /* PrimaryButtonView.m in Sources */,
D2092357244FA1EF0044AD09 /* ThreeLayerModelBase.swift in Sources */,
0A1B4A96233BB18F005B3FB4 /* CheckboxLabel.swift in Sources */,
0A21DB8B235E06EF00C160A2 /* MFDigitTextBox.m in Sources */,
D260D7B222D65BDD007E7233 /* MVMCoreUIPageControl.m in Sources */,
@ -2348,6 +2355,7 @@
94C0150A24215643005811A9 /* ActionTopAlertModel.swift in Sources */,
012A88DB238ED45900FE3DA1 /* CarouselModel.swift in Sources */,
D29DF28C21E7AC2B003B2FB9 /* ViewConstrainingView.m in Sources */,
D2092355244FA0FD0044AD09 /* ThreeLayerTemplateModelProtocol.swift in Sources */,
0AE14F64238315D2005417F8 /* TextField.swift in Sources */,
0AB764D124460F6300E7FE72 /* UIDatePicker+Extension.swift in Sources */,
D29DF17B21E69E1F003B2FB9 /* PrimaryButton.m in Sources */,

View File

@ -0,0 +1,17 @@
//
// ThreeLayerTemplateModelProtocol.swift
// MVMCoreUI
//
// Created by Scott Pfeil on 4/21/20.
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import Foundation
public protocol ThreeLayerTemplateModelProtocol: TemplateModelProtocol {
var anchorHeader: Bool { get set }
var header: MoleculeModelProtocol? { get set }
var anchorFooter: Bool { get set }
var footer: MoleculeModelProtocol? { get set }
}

View File

@ -8,7 +8,7 @@
import Foundation
@objcMembers public class CollectionTemplateModel: TemplateModel {
@objcMembers public class CollectionTemplateModel: ThreeLayerModelBase {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
@ -16,9 +16,7 @@ import Foundation
public override class var identifier: String {
return "collection"
}
public var header: MoleculeModelProtocol?
public var molecules: [CollectionItemModelProtocol & MoleculeModelProtocol]?
public var footer: MoleculeModelProtocol?
public var columns: Int?
//--------------------------------------------------
@ -37,8 +35,6 @@ import Foundation
private enum CodingKeys: String, CodingKey {
case molecules
case header
case footer
case columns
}
@ -49,8 +45,6 @@ import Foundation
required public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
molecules = try typeContainer.decodeModelsIfPresent(codingKey: .molecules)
header = try typeContainer.decodeModelIfPresent(codingKey: .header)
footer = try typeContainer.decodeModelIfPresent(codingKey: .footer)
columns = try typeContainer.decodeIfPresent(Int.self, forKey: .columns)
try super.init(from: decoder)
}
@ -59,8 +53,6 @@ import Foundation
try super.encode(to: encoder)
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encodeModelsIfPresent(molecules, forKey: .molecules)
try container.encodeModelIfPresent(header, forKey: .header)
try container.encodeModelIfPresent(footer, forKey: .footer)
try container.encodeIfPresent(columns, forKey: .columns)
}
}

View File

@ -8,7 +8,7 @@
import Foundation
@objcMembers public class ListPageTemplateModel: TemplateModel {
@objcMembers public class ListPageTemplateModel: ThreeLayerModelBase {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
@ -16,9 +16,7 @@ import Foundation
public override class var identifier: String {
return "list"
}
public var header: MoleculeModelProtocol?
public var molecules: [ListItemModelProtocol & MoleculeModelProtocol]?
public var footer: MoleculeModelProtocol?
public var line: LineModel?
//--------------------------------------------------
@ -37,8 +35,6 @@ import Foundation
private enum CodingKeys: String, CodingKey {
case molecules
case header
case footer
case line
}
@ -49,8 +45,6 @@ import Foundation
required public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
molecules = try typeContainer.decodeModelsIfPresent(codingKey: .molecules)
header = try typeContainer.decodeModelIfPresent(codingKey: .header)
footer = try typeContainer.decodeModelIfPresent(codingKey: .footer)
line = try typeContainer.decodeIfPresent(LineModel.self, forKey: .line)
try super.init(from: decoder)
}
@ -59,8 +53,6 @@ import Foundation
try super.encode(to: encoder)
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encodeModelsIfPresent(molecules, forKey: .molecules)
try container.encodeModelIfPresent(header, forKey: .header)
try container.encodeModelIfPresent(footer, forKey: .footer)
try container.encode(line, forKey: .line)
}
}

View File

@ -11,6 +11,12 @@ import UIKit
open class MoleculeStackTemplate: ThreeLayerViewController, TemplateProtocol {
var observer: NSKeyValueObservation?
public var templateModel: StackPageTemplateModel?
open override func handleNewData() {
topViewOutsideOfScroll = templateModel?.anchorHeader ?? false
bottomViewOutsideOfScroll = templateModel?.anchorFooter ?? false
super.handleNewData()
}
open override func parsePageJSON() throws {
try parseTemplate(json: loadObject?.pageJSON)

View File

@ -9,14 +9,11 @@
import Foundation
@objcMembers public class StackPageTemplateModel: TemplateModel {
@objcMembers public class StackPageTemplateModel: ThreeLayerModelBase {
public override class var identifier: String {
return "stack"
}
public var header: MoleculeModelProtocol?
public var moleculeStack: StackModel
public var footer: MoleculeModelProtocol?
public init(pageType: String, moleculeStack: StackModel) {
self.moleculeStack = moleculeStack
@ -24,16 +21,12 @@ import Foundation
}
private enum CodingKeys: String, CodingKey {
case header
case footer
case stack
}
required public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
moleculeStack = try typeContainer.decode(StackModel.self, forKey: .stack)
header = try typeContainer.decodeModelIfPresent(codingKey: .header)
footer = try typeContainer.decodeModelIfPresent(codingKey: .footer)
try super.init(from: decoder)
}
@ -41,7 +34,5 @@ import Foundation
try super.encode(to: encoder)
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(moleculeStack, forKey: .stack)
try container.encodeModelIfPresent(header, forKey: .header)
try container.encodeModelIfPresent(footer, forKey: .footer)
}
}

View File

@ -0,0 +1,49 @@
//
// ThreeLayerModelBase.swift
// MVMCoreUI
//
// Created by Scott Pfeil on 4/21/20.
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import Foundation
@objcMembers public class ThreeLayerModelBase: TemplateModel, ThreeLayerTemplateModelProtocol {
public var anchorHeader: Bool = false
public var header: MoleculeModelProtocol?
public var anchorFooter: Bool = false
public var footer: MoleculeModelProtocol?
public override init(pageType: String) {
super.init(pageType: pageType)
}
private enum CodingKeys: String, CodingKey {
case anchorHeader
case header
case anchorFooter
case footer
}
required public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
if let anchor = try typeContainer.decodeIfPresent(Bool.self, forKey: .anchorHeader) {
anchorHeader = anchor
}
header = try typeContainer.decodeModelIfPresent(codingKey: .header)
if let anchor = try typeContainer.decodeIfPresent(Bool.self, forKey: .anchorFooter) {
anchorFooter = anchor
}
footer = try typeContainer.decodeModelIfPresent(codingKey: .footer)
try super.init(from: decoder)
}
public override func encode(to encoder: Encoder) throws {
try super.encode(to: encoder)
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encodeIfPresent(anchorHeader, forKey: .anchorHeader)
try container.encodeModelIfPresent(header, forKey: .header)
try container.encodeIfPresent(anchorFooter, forKey: .anchorFooter)
try container.encodeModelIfPresent(footer, forKey: .footer)
}
}

View File

@ -8,13 +8,11 @@
import Foundation
@objcMembers public class ThreeLayerPageTemplateModel: TemplateModel {
@objcMembers public class ThreeLayerPageTemplateModel: ThreeLayerModelBase {
public override class var identifier: String {
return "threeLayer"
}
public var header: MoleculeModelProtocol?
public var middle: MoleculeModelProtocol?
public var footer: MoleculeModelProtocol?
public init(pageType: String, header: MoleculeModelProtocol?, middle: MoleculeModelProtocol?, footer: MoleculeModelProtocol?) {
super.init(pageType: pageType)
@ -24,24 +22,18 @@ import Foundation
}
private enum CodingKeys: String, CodingKey {
case header
case footer
case middle
}
required public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
header = try typeContainer.decodeModelIfPresent(codingKey: .header)
middle = try typeContainer.decodeModelIfPresent(codingKey: .middle)
footer = try typeContainer.decodeModelIfPresent(codingKey: .footer)
try super.init(from: decoder)
}
public override func encode(to encoder: Encoder) throws {
try super.encode(to: encoder)
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encodeModelIfPresent(header, forKey: .header)
try container.encodeModelIfPresent(header, forKey: .middle)
try container.encodeModelIfPresent(footer, forKey: .footer)
}
}

View File

@ -16,15 +16,10 @@ import UIKit
try super.parsePageJSON()
}
override open func viewDidLoad() {
super.viewDidLoad()
bottomViewOutsideOfScroll = true
// Do any additional setup after loading the view.
}
open override func handleNewData() {
topViewOutsideOfScroll = templateModel?.anchorHeader ?? false
bottomViewOutsideOfScroll = templateModel?.anchorFooter ?? false
super.handleNewData()
heightConstraint?.isActive = true
}
open override func viewForTop() -> UIView? {

View File

@ -18,6 +18,9 @@ open class ThreeLayerViewController: ProgrammaticScrollViewController {
var bottomView: UIView?
var useMargins: Bool = false
// The top view can be put outside of the scrolling area.
var topViewOutsideOfScroll = false
// The bottom view can be put outside of the scrolling area.
var bottomViewOutsideOfScroll = false
@ -118,13 +121,21 @@ extension ThreeLayerViewController {
topView = MVMCoreUICommonViewsUtility.commonView()
topView?.heightAnchor.constraint(equalToConstant: 0).isActive = true
}
guard let topView = topView, let contentView = contentView else {
return nil
guard var topView = topView else { return nil }
// Adds the top view outside the scroll if directed.
if topViewOutsideOfScroll {
topConstraint?.isActive = false;
addViewOutsideOfScrollViewTop(topView)
// Adds and returns an empty view to use for the internal logic.
topView = MVMCoreUICommonViewsUtility.commonView()
topView.heightAnchor.constraint(equalToConstant: 0).isActive = true
addViewInsideOfScrollViewTop(topView)
} else {
topConstraint?.isActive = true;
addViewInsideOfScrollViewTop(topView)
}
contentView.addSubview(topView)
NSLayoutConstraint.pinViewTop(toSuperview: topView, useMargins: useMargins, constant: 0).isActive = true
NSLayoutConstraint.pinViewLeft(toSuperview: topView, useMargins: useMargins, constant: 0).isActive = true
NSLayoutConstraint.pinViewRight(toSuperview: topView, useMargins: useMargins, constant: 0).isActive = true
return topView
}
@ -135,9 +146,7 @@ extension ThreeLayerViewController {
middleView = MVMCoreUICommonViewsUtility.commonView()
middleView?.heightAnchor.constraint(equalToConstant: 0).isActive = true
}
guard let middleView = middleView, let contentView = contentView else {
return nil
}
guard let middleView = middleView, let contentView = contentView else { return nil }
contentView.addSubview(middleView)
NSLayoutConstraint.pinViewLeft(toSuperview: middleView, useMargins: useMargins, constant: 0).isActive = true
NSLayoutConstraint.pinViewRight(toSuperview: middleView, useMargins: useMargins, constant: 0).isActive = true
@ -152,15 +161,17 @@ extension ThreeLayerViewController {
bottomView = MVMCoreUICommonViewsUtility.commonView()
bottomView?.heightAnchor.constraint(equalToConstant: 0).isActive = true
}
guard let bottomView = bottomView else {
return nil
}
guard var bottomView = bottomView else { return nil }
// Adds the bottom view outside the scroll if directed.
if bottomViewOutsideOfScroll {
bottomConstraint?.isActive = false;
addViewInsideOfScrollViewBottom(ViewConstrainingView.empty())
addViewOutsideOfScrollViewBottom(bottomView)
// Adds and returns an empty view to use for the internal logic.
bottomView = MVMCoreUICommonViewsUtility.commonView()
bottomView.heightAnchor.constraint(equalToConstant: 0).isActive = true
addViewInsideOfScrollViewBottom(bottomView)
} else {
bottomConstraint?.isActive = true;
addViewInsideOfScrollViewBottom(bottomView)
@ -221,6 +232,23 @@ extension ThreeLayerViewController {
}
}
func addViewInsideOfScrollViewTop(_ view: UIView) {
guard let contentView = contentView else { return }
contentView.addSubview(view)
NSLayoutConstraint.pinViewTop(toSuperview: view, useMargins: useMargins, constant: 0).isActive = true
NSLayoutConstraint.pinViewLeft(toSuperview: view, useMargins: useMargins, constant: 0).isActive = true
NSLayoutConstraint.pinViewRight(toSuperview: view, useMargins: useMargins, constant: 0).isActive = true
}
func addViewOutsideOfScrollViewTop(_ view: UIView) {
guard let scrollView = scrollView, let parentView = self.view else { return }
self.view?.addSubview(view)
scrollView.topAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
NSLayoutConstraint.pinViewLeft(toSuperview: view, useMargins: useMargins, constant: 0).isActive = true
NSLayoutConstraint.pinViewRight(toSuperview: view, useMargins: useMargins, constant: 0).isActive = true
view.topAnchor.constraint(equalTo: parentView.safeAreaLayoutGuide.topAnchor).isActive = true
}
func addViewInsideOfScrollViewBottom(_ view: UIView) {
guard let contentView = contentView else {
return

View File

@ -15,7 +15,7 @@ public extension MVMCoreUIViewControllerMappingObject {
@objc func registerTemplates() {
register(template: MoleculeStackTemplate.self)
register(template: MoleculeStackCenteredTemplate.self)
add(toTemplateViewControllerMapping: [StackCenteredPageTemplateModel.identifier: MVMCoreViewControllerProgrammaticMappingObject(with: MoleculeStackCenteredTemplate.self)!])
add(toTemplateViewControllerMapping: ["modalStack": MVMCoreViewControllerProgrammaticMappingObject(with: ModalMoleculeStackTemplate.self)!])
register(template: MoleculeListTemplate.self)