Fixes for sizing and base classes
This commit is contained in:
parent
d53b212241
commit
8c9ab45951
@ -250,6 +250,7 @@
|
|||||||
D264FA8E243BCD9A00D98315 /* CollectionTemplate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D264FA8D243BCD9A00D98315 /* CollectionTemplate.swift */; };
|
D264FA8E243BCD9A00D98315 /* CollectionTemplate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D264FA8D243BCD9A00D98315 /* CollectionTemplate.swift */; };
|
||||||
D264FA90243BCE6800D98315 /* ThreeLayerCollectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D264FA8F243BCE6800D98315 /* ThreeLayerCollectionViewController.swift */; };
|
D264FA90243BCE6800D98315 /* ThreeLayerCollectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D264FA8F243BCE6800D98315 /* ThreeLayerCollectionViewController.swift */; };
|
||||||
D264FAA1243CF66B00D98315 /* ContainerCollectionReusableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D264FAA0243CF66B00D98315 /* ContainerCollectionReusableView.swift */; };
|
D264FAA1243CF66B00D98315 /* ContainerCollectionReusableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D264FAA0243CF66B00D98315 /* ContainerCollectionReusableView.swift */; };
|
||||||
|
D264FAA3243E632F00D98315 /* ProgrammaticCollectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D264FAA2243E632F00D98315 /* ProgrammaticCollectionViewController.swift */; };
|
||||||
D268C70C2386DFFD007F2C1C /* MoleculeStackItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01EB368A23609801006832FA /* MoleculeStackItemModel.swift */; };
|
D268C70C2386DFFD007F2C1C /* MoleculeStackItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01EB368A23609801006832FA /* MoleculeStackItemModel.swift */; };
|
||||||
D268C70E238C22D7007F2C1C /* DropDownFilterTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D268C70D238C22D7007F2C1C /* DropDownFilterTableViewCell.swift */; };
|
D268C70E238C22D7007F2C1C /* DropDownFilterTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D268C70D238C22D7007F2C1C /* DropDownFilterTableViewCell.swift */; };
|
||||||
D26C5A6B23F4A40D007AEECE /* ListItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D26C5A6A23F4A40D007AEECE /* ListItemModel.swift */; };
|
D26C5A6B23F4A40D007AEECE /* ListItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D26C5A6A23F4A40D007AEECE /* ListItemModel.swift */; };
|
||||||
@ -656,6 +657,7 @@
|
|||||||
D264FA8D243BCD9A00D98315 /* CollectionTemplate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollectionTemplate.swift; sourceTree = "<group>"; };
|
D264FA8D243BCD9A00D98315 /* CollectionTemplate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollectionTemplate.swift; sourceTree = "<group>"; };
|
||||||
D264FA8F243BCE6800D98315 /* ThreeLayerCollectionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreeLayerCollectionViewController.swift; sourceTree = "<group>"; };
|
D264FA8F243BCE6800D98315 /* ThreeLayerCollectionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreeLayerCollectionViewController.swift; sourceTree = "<group>"; };
|
||||||
D264FAA0243CF66B00D98315 /* ContainerCollectionReusableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContainerCollectionReusableView.swift; sourceTree = "<group>"; };
|
D264FAA0243CF66B00D98315 /* ContainerCollectionReusableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContainerCollectionReusableView.swift; sourceTree = "<group>"; };
|
||||||
|
D264FAA2243E632F00D98315 /* ProgrammaticCollectionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgrammaticCollectionViewController.swift; sourceTree = "<group>"; };
|
||||||
D268C70D238C22D7007F2C1C /* DropDownFilterTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DropDownFilterTableViewCell.swift; sourceTree = "<group>"; };
|
D268C70D238C22D7007F2C1C /* DropDownFilterTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DropDownFilterTableViewCell.swift; sourceTree = "<group>"; };
|
||||||
D26C5A6A23F4A40D007AEECE /* ListItemModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListItemModel.swift; sourceTree = "<group>"; };
|
D26C5A6A23F4A40D007AEECE /* ListItemModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListItemModel.swift; sourceTree = "<group>"; };
|
||||||
D274CA322236A78900B01B62 /* FooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FooterView.swift; sourceTree = "<group>"; };
|
D274CA322236A78900B01B62 /* FooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FooterView.swift; sourceTree = "<group>"; };
|
||||||
@ -1485,6 +1487,7 @@
|
|||||||
D2A92881241AAB67004E01C6 /* ScrollingViewController.swift */,
|
D2A92881241AAB67004E01C6 /* ScrollingViewController.swift */,
|
||||||
D2A92883241ACB25004E01C6 /* ProgrammaticScrollViewController.swift */,
|
D2A92883241ACB25004E01C6 /* ProgrammaticScrollViewController.swift */,
|
||||||
D2A92885241ACD99004E01C6 /* ProgrammaticTableViewController.swift */,
|
D2A92885241ACD99004E01C6 /* ProgrammaticTableViewController.swift */,
|
||||||
|
D264FAA2243E632F00D98315 /* ProgrammaticCollectionViewController.swift */,
|
||||||
);
|
);
|
||||||
path = BaseControllers;
|
path = BaseControllers;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -2162,6 +2165,7 @@
|
|||||||
C6FA7D5323C77A4A00A3614A /* StringAndMoleculeStack.swift in Sources */,
|
C6FA7D5323C77A4A00A3614A /* StringAndMoleculeStack.swift in Sources */,
|
||||||
011D958524042432000E3791 /* RulesProtocol.swift in Sources */,
|
011D958524042432000E3791 /* RulesProtocol.swift in Sources */,
|
||||||
94AF4A3F23E9D13900676048 /* MFCaretButton.m in Sources */,
|
94AF4A3F23E9D13900676048 /* MFCaretButton.m in Sources */,
|
||||||
|
D264FAA3243E632F00D98315 /* ProgrammaticCollectionViewController.swift in Sources */,
|
||||||
D29DF27A21E7A533003B2FB9 /* MVMCoreUISession.m in Sources */,
|
D29DF27A21E7A533003B2FB9 /* MVMCoreUISession.m in Sources */,
|
||||||
D2A5146B2214905000345BFB /* ThreeLayerViewController.swift in Sources */,
|
D2A5146B2214905000345BFB /* ThreeLayerViewController.swift in Sources */,
|
||||||
526A265E240D200500B0D828 /* ListTwoColumnCompareChanges.swift in Sources */,
|
526A265E240D200500B0D828 /* ListTwoColumnCompareChanges.swift in Sources */,
|
||||||
|
|||||||
@ -64,7 +64,6 @@ import Foundation
|
|||||||
}
|
}
|
||||||
|
|
||||||
open override func shouldFinishProcessingLoad(_ loadObject: MVMCoreLoadObject, error: AutoreleasingUnsafeMutablePointer<MVMCoreErrorObject>) -> Bool {
|
open override func shouldFinishProcessingLoad(_ loadObject: MVMCoreLoadObject, error: AutoreleasingUnsafeMutablePointer<MVMCoreErrorObject>) -> Bool {
|
||||||
|
|
||||||
guard super.shouldFinishProcessingLoad(loadObject, error: error) else { return false }
|
guard super.shouldFinishProcessingLoad(loadObject, error: error) else { return false }
|
||||||
|
|
||||||
// This template requires atleast one of the three layers.
|
// This template requires atleast one of the three layers.
|
||||||
@ -103,8 +102,8 @@ import Foundation
|
|||||||
}
|
}
|
||||||
|
|
||||||
open override func numberOfSections(in collectionView: UICollectionView) -> Int {
|
open override func numberOfSections(in collectionView: UICollectionView) -> Int {
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
open override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
open override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
||||||
guard let moleculeInfo = moleculesInfo?[indexPath.row]
|
guard let moleculeInfo = moleculesInfo?[indexPath.row]
|
||||||
@ -124,7 +123,7 @@ import Foundation
|
|||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|
||||||
/// Returns the (identifier, class) of the molecule for the given map.
|
/// Returns the (identifier, class) of the molecule for the given map.
|
||||||
func getMoleculeInfo(with item: (CollectionItemModelProtocol & MoleculeModelProtocol)?) -> (identifier: String, class: AnyClass, molecule: CollectionItemModelProtocol & MoleculeModelProtocol)? {
|
open func getMoleculeInfo(with item: (CollectionItemModelProtocol & MoleculeModelProtocol)?) -> (identifier: String, class: AnyClass, molecule: CollectionItemModelProtocol & MoleculeModelProtocol)? {
|
||||||
guard let item = item,
|
guard let item = item,
|
||||||
let moleculeClass = MoleculeObjectMapping.shared()?.getMoleculeClass(item) else { return nil }
|
let moleculeClass = MoleculeObjectMapping.shared()?.getMoleculeClass(item) else { return nil }
|
||||||
let moleculeName = moleculeClass.nameForReuse(with: item, delegateObjectIVar) ?? item.moleculeName
|
let moleculeName = moleculeClass.nameForReuse(with: item, delegateObjectIVar) ?? item.moleculeName
|
||||||
@ -132,7 +131,7 @@ import Foundation
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Sets up the molecule list and ensures no errors loading all content.
|
/// Sets up the molecule list and ensures no errors loading all content.
|
||||||
func getMoleculeInfoList() -> [(identifier: String, class: AnyClass, molecule: (CollectionItemModelProtocol & MoleculeModelProtocol))]? {
|
open func getMoleculeInfoList() -> [(identifier: String, class: AnyClass, molecule: (CollectionItemModelProtocol & MoleculeModelProtocol))]? {
|
||||||
|
|
||||||
var moleculeList: [(identifier: String, class: AnyClass, molecule: CollectionItemModelProtocol & MoleculeModelProtocol)] = []
|
var moleculeList: [(identifier: String, class: AnyClass, molecule: CollectionItemModelProtocol & MoleculeModelProtocol)] = []
|
||||||
|
|
||||||
@ -148,7 +147,7 @@ import Foundation
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Sets up the header, footer, molecule list and ensures no errors loading all content.
|
/// Sets up the header, footer, molecule list and ensures no errors loading all content.
|
||||||
func setup() {
|
open func setup() {
|
||||||
moleculesInfo = getMoleculeInfoList()
|
moleculesInfo = getMoleculeInfoList()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -46,7 +46,7 @@ open class CollectionViewCell: UICollectionViewCell, MoleculeViewProtocol, MVMCo
|
|||||||
open func updateView(_ size: CGFloat) {
|
open func updateView(_ size: CGFloat) {
|
||||||
containerHelper.updateViewMargins(contentView, model: model, size: size)
|
containerHelper.updateViewMargins(contentView, model: model, size: size)
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
print("\(self.contentView.directionalLayoutMargins.leading)")
|
print("leading \(self.contentView.directionalLayoutMargins.leading)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -14,12 +14,16 @@ public class ContainerCollectionReusableView: UICollectionReusableView {
|
|||||||
var bottomConstraint: NSLayoutConstraint?
|
var bottomConstraint: NSLayoutConstraint?
|
||||||
|
|
||||||
public func addAndContain(view: UIView) {
|
public func addAndContain(view: UIView) {
|
||||||
|
guard self.view != view else { return }
|
||||||
self.view?.removeFromSuperview()
|
self.view?.removeFromSuperview()
|
||||||
view.setContentCompressionResistancePriority(.required, for: .vertical)
|
view.setContentCompressionResistancePriority(.required, for: .vertical)
|
||||||
addSubview(view)
|
addSubview(view)
|
||||||
self.view = view
|
self.view = view
|
||||||
let constraints = NSLayoutConstraint.constraintPinSubview(toSuperview: view)
|
topConstraint = view.topAnchor.constraint(equalTo: topAnchor)
|
||||||
topConstraint = constraints?[ConstraintTop] as? NSLayoutConstraint
|
topConstraint?.isActive = true
|
||||||
bottomConstraint = constraints?[ConstraintBot] as? NSLayoutConstraint
|
bottomConstraint = bottomAnchor.constraint(equalTo: view.bottomAnchor)
|
||||||
|
bottomConstraint?.isActive = true
|
||||||
|
rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
|
||||||
|
view.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,80 @@
|
|||||||
|
//
|
||||||
|
// ProgrammaticCollectionViewController.swift
|
||||||
|
// MVMCoreUI
|
||||||
|
//
|
||||||
|
// Created by Scott Pfeil on 4/8/20.
|
||||||
|
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
@objc open class ProgrammaticCollectionViewController: ScrollingViewController {
|
||||||
|
|
||||||
|
public var collectionView: UICollectionView?
|
||||||
|
|
||||||
|
open override func loadView() {
|
||||||
|
let view = UIView()
|
||||||
|
view.backgroundColor = .white
|
||||||
|
|
||||||
|
let collection = createCollectionView()
|
||||||
|
view.addSubview(collection)
|
||||||
|
NSLayoutConstraint.constraintPinSubview(toSuperview: collection)
|
||||||
|
|
||||||
|
collectionView = collection
|
||||||
|
scrollView = collectionView
|
||||||
|
self.view = view
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A place to register cells with the collectionView
|
||||||
|
open func registerCells() {}
|
||||||
|
|
||||||
|
open override func viewDidLoad() {
|
||||||
|
super.viewDidLoad()
|
||||||
|
registerCells()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates the layout for the collection.
|
||||||
|
open func createCollectionViewLayout() -> UICollectionViewLayout {
|
||||||
|
let layout = UICollectionViewFlowLayout()
|
||||||
|
layout.scrollDirection = .vertical
|
||||||
|
layout.minimumLineSpacing = 0
|
||||||
|
layout.minimumInteritemSpacing = 0
|
||||||
|
layout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
|
||||||
|
return layout
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates the collection view.
|
||||||
|
open func createCollectionView() -> UICollectionView {
|
||||||
|
let collection = UICollectionView(frame: .zero, collectionViewLayout: createCollectionViewLayout())
|
||||||
|
collection.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
collection.dataSource = self
|
||||||
|
collection.delegate = self
|
||||||
|
collection.showsHorizontalScrollIndicator = false
|
||||||
|
collection.backgroundColor = .white
|
||||||
|
collection.isAccessibilityElement = false
|
||||||
|
collection.contentInsetAdjustmentBehavior = .always
|
||||||
|
return collection
|
||||||
|
}
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
collectionView?.delegate = nil
|
||||||
|
collectionView?.dataSource = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension ProgrammaticCollectionViewController: UICollectionViewDataSource {
|
||||||
|
open func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
open func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
||||||
|
return UICollectionViewCell()
|
||||||
|
}
|
||||||
|
|
||||||
|
open func numberOfSections(in collectionView: UICollectionView) -> Int {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension ProgrammaticCollectionViewController: UICollectionViewDelegate {
|
||||||
|
}
|
||||||
@ -42,6 +42,11 @@ open class ProgrammaticTableViewController: ProgrammaticScrollViewController, UI
|
|||||||
self.view = view
|
self.view = view
|
||||||
}
|
}
|
||||||
|
|
||||||
|
open override func viewDidLoad() {
|
||||||
|
super.viewDidLoad()
|
||||||
|
registerWithTable()
|
||||||
|
}
|
||||||
|
|
||||||
/// This class should create the table view that will be used here. Subclass this for different table styles.
|
/// This class should create the table view that will be used here. Subclass this for different table styles.
|
||||||
open func createTableView() -> UITableView {
|
open func createTableView() -> UITableView {
|
||||||
let tableView = UITableView(frame: .zero, style: .grouped)
|
let tableView = UITableView(frame: .zero, style: .grouped)
|
||||||
|
|||||||
@ -8,73 +8,18 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
@objc open class ThreeLayerCollectionViewController: ScrollingViewController, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
|
@objc open class ThreeLayerCollectionViewController: ProgrammaticCollectionViewController, UICollectionViewDelegateFlowLayout {
|
||||||
public var collectionView: UICollectionView?
|
|
||||||
|
|
||||||
// The three main views
|
// The three main views
|
||||||
private var topView: UIView?
|
private var topView: UIView?
|
||||||
private var bottomView: UIView?
|
private var bottomView: UIView?
|
||||||
private var headerView: ContainerCollectionReusableView?
|
private var headerView: ContainerCollectionReusableView?
|
||||||
private var footerView: ContainerCollectionReusableView?
|
private var footerView: ContainerCollectionReusableView?
|
||||||
var useMargins: Bool = true
|
|
||||||
private let headerID = "header"
|
private let headerID = "header"
|
||||||
private let footerID = "footer"
|
private let footerID = "footer"
|
||||||
|
|
||||||
//MARK: - MFViewController
|
/// Updates the padding for flexible space (header or footer)
|
||||||
open override func updateViews() {
|
private func updateFlexibleSpace() {
|
||||||
super.updateViews()
|
|
||||||
let width = view.bounds.width
|
|
||||||
if let topView = topView as? MVMCoreViewProtocol {
|
|
||||||
topView.updateView(width)
|
|
||||||
// showHeader(width)
|
|
||||||
}
|
|
||||||
if let bottomView = bottomView as? MVMCoreViewProtocol {
|
|
||||||
bottomView.updateView(width)
|
|
||||||
//showFooter(width)
|
|
||||||
}
|
|
||||||
self.collectionView?.collectionViewLayout.invalidateLayout()
|
|
||||||
}
|
|
||||||
|
|
||||||
open override func handleNewData() {
|
|
||||||
super.handleNewData()
|
|
||||||
createViewForTableHeader()
|
|
||||||
createViewForTableFooter()
|
|
||||||
collectionView?.reloadData()
|
|
||||||
}
|
|
||||||
|
|
||||||
override open func viewDidLoad() {
|
|
||||||
let collection = createCollectionView()
|
|
||||||
collectionView = collection
|
|
||||||
view.addSubview(collection)
|
|
||||||
NSLayoutConstraint.constraintPinSubview(toSuperview: collection)
|
|
||||||
scrollView = collectionView
|
|
||||||
|
|
||||||
registerCells()
|
|
||||||
|
|
||||||
super.viewDidLoad()
|
|
||||||
// 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 = collectionView else { return }
|
guard let tableView = collectionView else { return }
|
||||||
|
|
||||||
let minimumSpace: CGFloat = minimumFillSpace()
|
let minimumSpace: CGFloat = minimumFillSpace()
|
||||||
@ -105,29 +50,70 @@ import Foundation
|
|||||||
currentSpaceForCompare = currentSpace * 2;
|
currentSpaceForCompare = currentSpace * 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if !MVMCoreGetterUtility.cgfequalwiththreshold(newSpace, currentSpaceForCompare, 0.1) {
|
if !MVMCoreGetterUtility.cgfequalwiththreshold(newSpace, currentSpaceForCompare, 2) {
|
||||||
if fillTop && fillBottom {
|
if fillTop && fillBottom {
|
||||||
// space both
|
// space both
|
||||||
let half = newSpace / 2
|
let half = newSpace / 2
|
||||||
headerView?.bottomConstraint?.constant = half
|
headerView?.bottomConstraint?.constant = half
|
||||||
footerView?.topConstraint?.constant = half
|
footerView?.topConstraint?.constant = half
|
||||||
collectionView?.invalidateIntrinsicContentSize()
|
collectionView?.collectionViewLayout.invalidateLayout()
|
||||||
} else if fillTop {
|
} 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.
|
// 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.
|
||||||
headerView?.bottomConstraint?.constant = newSpace
|
headerView?.bottomConstraint?.constant = newSpace
|
||||||
collectionView?.invalidateIntrinsicContentSize()
|
collectionView?.collectionViewLayout.invalidateLayout()
|
||||||
} else if fillBottom {
|
} else if fillBottom {
|
||||||
// Only bottom is spaced.
|
// Only bottom is spaced.
|
||||||
print("newSpace \(newSpace)")
|
|
||||||
footerView?.topConstraint?.constant = newSpace
|
footerView?.topConstraint?.constant = newSpace
|
||||||
collectionView?.invalidateIntrinsicContentSize()
|
collectionView?.collectionViewLayout.invalidateLayout()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//MARK: - MFViewController
|
||||||
|
open override func updateViews() {
|
||||||
|
super.updateViews()
|
||||||
|
let width = view.bounds.width
|
||||||
|
if let topView = topView as? MVMCoreViewProtocol {
|
||||||
|
topView.updateView(width)
|
||||||
|
}
|
||||||
|
if let bottomView = bottomView as? MVMCoreViewProtocol {
|
||||||
|
bottomView.updateView(width)
|
||||||
|
}
|
||||||
|
invalidateCollectionLayout()
|
||||||
|
}
|
||||||
|
|
||||||
|
open override func handleNewData() {
|
||||||
|
super.handleNewData()
|
||||||
|
createViewForHeader()
|
||||||
|
createViewForFooter()
|
||||||
|
reloadCollectionData()
|
||||||
|
}
|
||||||
|
|
||||||
|
override open func viewDidLoad() {
|
||||||
|
super.viewDidLoad()
|
||||||
|
// 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 collection rows, nil to fill. 0 default
|
||||||
|
open func spaceBelowTopView() -> CGFloat? {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Space between the bottom view and the collection rows, 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
|
||||||
|
}
|
||||||
|
|
||||||
//MARK: - Header Footer
|
//MARK: - Header Footer
|
||||||
/// Gets the top view and adds it to a spacing view, headerView, and then calls showHeader.
|
/// Creates the top view.
|
||||||
open func createViewForTableHeader() {
|
open func createViewForHeader() {
|
||||||
guard let topView = viewForTop() else {
|
guard let topView = viewForTop() else {
|
||||||
self.topView = nil
|
self.topView = nil
|
||||||
self.headerView = nil
|
self.headerView = nil
|
||||||
@ -136,8 +122,8 @@ import Foundation
|
|||||||
self.topView = topView
|
self.topView = topView
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the bottom view and adds it to a spacing view, footerView, and then calls showFooter.
|
/// Creates the footer
|
||||||
open func createViewForTableFooter() {
|
open func createViewForFooter() {
|
||||||
guard let bottomView = viewForBottom() else {
|
guard let bottomView = viewForBottom() else {
|
||||||
self.bottomView = nil
|
self.bottomView = nil
|
||||||
self.footerView = nil
|
self.footerView = nil
|
||||||
@ -145,60 +131,7 @@ import Foundation
|
|||||||
}
|
}
|
||||||
self.bottomView = bottomView
|
self.bottomView = bottomView
|
||||||
}
|
}
|
||||||
|
|
||||||
// /// Takes the current headerView and adds it to the tableHeaderView
|
|
||||||
// func showHeader(_ sizingWidth: CGFloat?) {
|
|
||||||
// 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.
|
|
||||||
// headerView.setNeedsLayout()
|
|
||||||
// headerView.layoutIfNeeded()
|
|
||||||
// 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(_ sizingWidth: CGFloat?) {
|
|
||||||
// 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
|
|
||||||
// view.safeAreaLayoutGuide.bottomAnchor.constraint(equalTo: footerView.bottomAnchor).isActive = true
|
|
||||||
// safeAreaView = MVMCoreUICommonViewsUtility.getAndSetupSafeAreaView(on: view)
|
|
||||||
// safeAreaView?.backgroundColor = bottomView?.backgroundColor
|
|
||||||
// } 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
|
//MARK: - Functions to subclass
|
||||||
/// Subclass for a top view.
|
/// Subclass for a top view.
|
||||||
open func viewForTop() -> UIView? {
|
open func viewForTop() -> UIView? {
|
||||||
@ -210,85 +143,65 @@ import Foundation
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
open func createCollectionViewLayout() -> UICollectionViewLayout {
|
|
||||||
let layout = UICollectionViewFlowLayout()
|
|
||||||
layout.scrollDirection = .vertical
|
|
||||||
layout.minimumLineSpacing = 0
|
|
||||||
layout.minimumInteritemSpacing = 0
|
|
||||||
layout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
|
|
||||||
return layout
|
|
||||||
}
|
|
||||||
|
|
||||||
open func createCollectionView() -> UICollectionView {
|
|
||||||
let collection = UICollectionView(frame: .zero, collectionViewLayout: createCollectionViewLayout())
|
|
||||||
collection.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
collection.dataSource = self
|
|
||||||
collection.delegate = self
|
|
||||||
collection.showsHorizontalScrollIndicator = false
|
|
||||||
collection.backgroundColor = .white
|
|
||||||
collection.isAccessibilityElement = false
|
|
||||||
collection.contentInsetAdjustmentBehavior = .always
|
|
||||||
return collection
|
|
||||||
}
|
|
||||||
|
|
||||||
deinit {
|
|
||||||
collectionView?.delegate = nil
|
|
||||||
collectionView?.dataSource = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
//MARK: - Collection
|
//MARK: - Collection
|
||||||
|
|
||||||
open func registerCells() {
|
/// Should be used to refresh the layout of the collection view. Updates flexible padding.
|
||||||
|
open func invalidateCollectionLayout() {
|
||||||
|
self.collectionView?.collectionViewLayout.invalidateLayout()
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.1, execute: {
|
||||||
|
self.updateFlexibleSpace()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Should be used to reload the data of the collection view. Updates flexible padding.
|
||||||
|
open func reloadCollectionData() {
|
||||||
|
collectionView?.reloadData()
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.1, execute: {
|
||||||
|
self.updateFlexibleSpace()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
open override func registerCells() {
|
||||||
|
super.registerCells()
|
||||||
collectionView?.register(ContainerCollectionReusableView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: headerID)
|
collectionView?.register(ContainerCollectionReusableView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: headerID)
|
||||||
collectionView?.register(ContainerCollectionReusableView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter, withReuseIdentifier: footerID)
|
collectionView?.register(ContainerCollectionReusableView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter, withReuseIdentifier: footerID)
|
||||||
}
|
}
|
||||||
|
|
||||||
open func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
|
open override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
open func numberOfSections(in collectionView: UICollectionView) -> Int {
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
open func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
|
||||||
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionItem", for: indexPath) as! MoleculeCollectionViewCell
|
|
||||||
let labelModel = LabelModel(text: "hello")
|
|
||||||
let model = MoleculeCollectionItemModel(with: labelModel)
|
|
||||||
cell.set(with: model, delegateObjectIVar, nil)
|
|
||||||
return cell
|
|
||||||
}
|
|
||||||
|
|
||||||
open func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
|
open func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
|
||||||
guard let view = headerView ?? topView,
|
guard let _ = topView,
|
||||||
section == 0 else { return .zero }
|
section == 0 else { return .zero }
|
||||||
|
let header = headerView ?? self.collectionView(collectionView, viewForSupplementaryElementOfKind: UICollectionView.elementKindSectionHeader, at: IndexPath(row: 0, section: section))
|
||||||
|
|
||||||
// Use this view to calculate the optimal size based on the collection view's width
|
// Use this view to calculate the optimal size based on the collection view's width
|
||||||
return view.systemLayoutSizeFitting(CGSize(width: collectionView.frame.width, height: UIView.layoutFittingExpandedSize.height),
|
return header.systemLayoutSizeFitting(CGSize(width: collectionView.frame.width, height: UIView.layoutFittingExpandedSize.height),
|
||||||
withHorizontalFittingPriority: .required, // Width is fixed
|
withHorizontalFittingPriority: .required, // Width is fixed
|
||||||
verticalFittingPriority: .fittingSizeLevel) // Height can be as large as needed
|
verticalFittingPriority: .fittingSizeLevel) // Height can be as large as needed
|
||||||
}
|
}
|
||||||
|
|
||||||
open func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize {
|
open func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize {
|
||||||
guard let view = footerView ?? bottomView,
|
guard let _ = bottomView,
|
||||||
section == numberOfSections(in: collectionView) - 1 else { return .zero }
|
section == numberOfSections(in: collectionView) - 1 else { return .zero }
|
||||||
|
let footer = footerView ?? self.collectionView(collectionView, viewForSupplementaryElementOfKind: UICollectionView.elementKindSectionFooter, at: IndexPath(row: 0, section: section))
|
||||||
|
|
||||||
// Use this view to calculate the optimal size based on the collection view's width
|
// Use this view to calculate the optimal size based on the collection view's width
|
||||||
let size = view.systemLayoutSizeFitting(CGSize(width: collectionView.frame.width, height: UIView.layoutFittingExpandedSize.height),
|
let size = footer.systemLayoutSizeFitting(CGSize(width: collectionView.frame.width, height: UIView.layoutFittingExpandedSize.height),
|
||||||
withHorizontalFittingPriority: .required, // Width is fixed
|
withHorizontalFittingPriority: .required, // Width is fixed
|
||||||
verticalFittingPriority: .fittingSizeLevel) // Height can be as large as needed
|
verticalFittingPriority: .fittingSizeLevel) // Height can be as large as needed
|
||||||
print("SIZEEE \(size.height) \(String(describing: footerView?.topConstraint?.constant))")
|
|
||||||
return size
|
return size
|
||||||
}
|
}
|
||||||
|
|
||||||
open func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
|
open func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
|
||||||
if (kind == UICollectionView.elementKindSectionFooter) {
|
if kind == UICollectionView.elementKindSectionFooter {
|
||||||
let footerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: footerID, for: indexPath) as! ContainerCollectionReusableView
|
let footerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: footerID, for: indexPath) as! ContainerCollectionReusableView
|
||||||
footerView.addAndContain(view: bottomView!)
|
footerView.addAndContain(view: bottomView!)
|
||||||
footerView.topConstraint?.constant = spaceAboveBottomView() ?? 0
|
footerView.topConstraint?.constant = spaceAboveBottomView() ?? 0
|
||||||
self.footerView = footerView
|
self.footerView = footerView
|
||||||
return footerView
|
return footerView
|
||||||
} else if (kind == UICollectionView.elementKindSectionHeader) {
|
} else if kind == UICollectionView.elementKindSectionHeader {
|
||||||
let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: headerID, for: indexPath) as! ContainerCollectionReusableView
|
let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: headerID, for: indexPath) as! ContainerCollectionReusableView
|
||||||
headerView.addAndContain(view: topView!)
|
headerView.addAndContain(view: topView!)
|
||||||
headerView.bottomConstraint?.constant = spaceBelowTopView() ?? 0
|
headerView.bottomConstraint?.constant = spaceBelowTopView() ?? 0
|
||||||
|
|||||||
@ -24,7 +24,7 @@ import UIKit
|
|||||||
|
|
||||||
public var formValidator: FormValidator?
|
public var formValidator: FormValidator?
|
||||||
|
|
||||||
public var needsUpdateUI = true
|
public var needsUpdateUI = false
|
||||||
private var observingForResponses = false
|
private var observingForResponses = false
|
||||||
private var initialLoadFinished = false
|
private var initialLoadFinished = false
|
||||||
private var previousScreenSize = CGSize.zero
|
private var previousScreenSize = CGSize.zero
|
||||||
@ -155,8 +155,8 @@ import UIKit
|
|||||||
/// Calls processNewData and then sets the ui to update with updateView
|
/// Calls processNewData and then sets the ui to update with updateView
|
||||||
open func handleNewDataAndUpdateUI() {
|
open func handleNewDataAndUpdateUI() {
|
||||||
handleNewData()
|
handleNewData()
|
||||||
self.needsUpdateUI = true
|
needsUpdateUI = true
|
||||||
self.view.setNeedsLayout()
|
view.setNeedsLayout()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Processes any new data. Called after the page is loaded the first time and on response updates for this page,
|
/// Processes any new data. Called after the page is loaded the first time and on response updates for this page,
|
||||||
@ -170,9 +170,9 @@ import UIKit
|
|||||||
navigationModel.line = LineModel(type: .none)
|
navigationModel.line = LineModel(type: .none)
|
||||||
}
|
}
|
||||||
pageModel?.navigationItem = navigationModel
|
pageModel?.navigationItem = navigationModel
|
||||||
if self.formValidator == nil {
|
if formValidator == nil {
|
||||||
let rules = pageModel?.formRules
|
let rules = pageModel?.formRules
|
||||||
self.formValidator = FormValidator(rules)
|
formValidator = FormValidator(rules)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,10 +268,10 @@ import UIKit
|
|||||||
initialLoad()
|
initialLoad()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle data on load
|
// Handle data for first load. Dispatched to allow subclasses to finish their view did load implementations.
|
||||||
handleNewData()
|
DispatchQueue.main.async {
|
||||||
|
self.handleNewDataAndUpdateUI()
|
||||||
view.setNeedsLayout()
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
open override func viewDidLayoutSubviews() {
|
open override func viewDidLayoutSubviews() {
|
||||||
|
|||||||
@ -168,8 +168,8 @@
|
|||||||
topInset = scrollview.adjustedContentInset.top;
|
topInset = scrollview.adjustedContentInset.top;
|
||||||
bottomInset = scrollview.adjustedContentInset.bottom;
|
bottomInset = scrollview.adjustedContentInset.bottom;
|
||||||
}
|
}
|
||||||
|
|
||||||
CGFloat remainingSpace = frameHeight - contentSizeHeight - topInset - bottomInset;
|
CGFloat remainingSpace = frameHeight - contentSizeHeight - topInset - bottomInset;
|
||||||
|
NSLog(@"scc SPACCEEE remaining: %f frame: %f, content: %f, insets:(%f,%f)",remainingSpace,frameHeight,contentSizeHeight,topInset,bottomInset);
|
||||||
return remainingSpace - 1;
|
return remainingSpace - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user