This commit is contained in:
Pfeil, Scott Robert 2020-04-22 14:03:02 -04:00
parent 9366469f35
commit 02e1de9b88
3 changed files with 25 additions and 62 deletions

View File

@ -17,6 +17,8 @@ import Foundation
private var footerView: ContainerCollectionReusableView? private var footerView: ContainerCollectionReusableView?
private let headerID = "header" private let headerID = "header"
private let footerID = "footer" private let footerID = "footer"
public var bottomViewOutsideOfScrollArea: Bool = false
public var topViewOutsideOfScrollArea: Bool = false
/// Updates the padding for flexible space (header or footer) /// Updates the padding for flexible space (header or footer)
private func updateFlexibleSpace() { private func updateFlexibleSpace() {
@ -41,16 +43,8 @@ import Foundation
} }
guard fillTop || fillBottom else { return } guard fillTop || fillBottom else { return }
let newSpace = MVMCoreUIUtility.getVariableConstraintHeight(currentSpace, in: tableView, minimumHeight: totalMinimumSpace) let newSpace = MVMCoreUIUtility.getVariableConstraintHeight(currentSpace, in: tableView, minimumHeight: totalMinimumSpace)
if !MVMCoreGetterUtility.cgfequalwiththreshold(newSpace, currentSpace, 1) {
// If the bottom view is outside of the scroll, then only the top view constraint is being used, so we have to double it to account for the bottom constraint not being there when we compare to the new value.
var currentSpaceForCompare: CGFloat = currentSpace
if fillTop {
currentSpaceForCompare = currentSpace * 2;
}
if !MVMCoreGetterUtility.cgfequalwiththreshold(newSpace, currentSpaceForCompare, 1) {
if fillTop && fillBottom { if fillTop && fillBottom {
// space both // space both
let half = newSpace / 2 let half = newSpace / 2
@ -89,11 +83,11 @@ import Foundation
self.invalidateCollectionLayout() self.invalidateCollectionLayout()
} }
} }
open override func handleNewData() { open override func handleNewData() {
super.handleNewData() super.handleNewData()
createViewForHeader() topView = viewForTop()
createViewForFooter() bottomView = viewForBottom()
reloadCollectionData() reloadCollectionData()
} }
@ -118,27 +112,6 @@ import Foundation
open func minimumFillSpace() -> CGFloat { open func minimumFillSpace() -> CGFloat {
return 0 return 0
} }
//MARK: - Header Footer
/// Creates the top view.
open func createViewForHeader() {
guard let topView = viewForTop() else {
self.topView = nil
self.headerView = nil
return
}
self.topView = topView
}
/// Creates the footer
open func createViewForFooter() {
guard let bottomView = viewForBottom() else {
self.bottomView = nil
self.footerView = nil
return
}
self.bottomView = bottomView
}
//MARK: - Functions to subclass //MARK: - Functions to subclass
/// Subclass for a top view. /// Subclass for a top view.
@ -187,18 +160,14 @@ import Foundation
} }
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 _ = topView, guard section == 0 else { return .zero }
section == 0 else { return .zero }
// Calculate the height of the header since apple doesn't support autolayout. Width is fixed, height is tall as content. // Calculate the height of the header since apple doesn't support autolayout. Width is fixed, height is tall as content.
let header = headerView ?? self.collectionView(collectionView, viewForSupplementaryElementOfKind: UICollectionView.elementKindSectionHeader, at: IndexPath(row: 0, section: section)) let header = headerView ?? self.collectionView(collectionView, viewForSupplementaryElementOfKind: UICollectionView.elementKindSectionHeader, at: IndexPath(row: 0, section: section))
return header.systemLayoutSizeFitting(CGSize(width: collectionView.frame.width, height: UIView.layoutFittingExpandedSize.height), withHorizontalFittingPriority: .required, verticalFittingPriority: .fittingSizeLevel) return header.systemLayoutSizeFitting(CGSize(width: collectionView.frame.width, height: UIView.layoutFittingExpandedSize.height), withHorizontalFittingPriority: .required, verticalFittingPriority: .fittingSizeLevel)
} }
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 _ = bottomView, guard section == numberOfSections(in: collectionView) - 1 else { return .zero }
section == numberOfSections(in: collectionView) - 1 else { return .zero }
// Calculate the height of the footr since apple doesn't support autolayout. Width is fixed, height is tall as content. // Calculate the height of the footr since apple doesn't support autolayout. Width is fixed, height is tall as content.
let footer = footerView ?? self.collectionView(collectionView, viewForSupplementaryElementOfKind: UICollectionView.elementKindSectionFooter, at: IndexPath(row: 0, section: section)) let footer = footerView ?? self.collectionView(collectionView, viewForSupplementaryElementOfKind: UICollectionView.elementKindSectionFooter, at: IndexPath(row: 0, section: section))
return footer.systemLayoutSizeFitting(CGSize(width: collectionView.frame.width, height: UIView.layoutFittingExpandedSize.height), withHorizontalFittingPriority: .required, verticalFittingPriority: .fittingSizeLevel) return footer.systemLayoutSizeFitting(CGSize(width: collectionView.frame.width, height: UIView.layoutFittingExpandedSize.height), withHorizontalFittingPriority: .required, verticalFittingPriority: .fittingSizeLevel)
@ -207,13 +176,15 @@ import Foundation
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!) let bottomView = self.bottomView ?? MVMCoreUICommonViewsUtility.getView(with: 0)
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!) let topView = self.topView ?? MVMCoreUICommonViewsUtility.getView(with: 0)
headerView.addAndContain(view: topView)
headerView.bottomConstraint?.constant = spaceBelowTopView() ?? 0 headerView.bottomConstraint?.constant = spaceBelowTopView() ?? 0
self.headerView = headerView self.headerView = headerView
return headerView return headerView

View File

@ -92,15 +92,8 @@ open class ThreeLayerTableViewController: ProgrammaticTableViewController {
guard fillTop || fillBottom else { return } guard fillTop || fillBottom else { return }
let newSpace = MVMCoreUIUtility.getVariableConstraintHeight(currentSpace, in: tableView, minimumHeight: totalMinimumSpace) let newSpace = MVMCoreUIUtility.getVariableConstraintHeight(currentSpace, in: tableView, minimumHeight: totalMinimumSpace)
// If the bottom view is outside of the scroll, then only the top view constraint is being used, so we have to double it to account for the bottom constraint not being there when we compare to the new value.
var currentSpaceForCompare: CGFloat = currentSpace
if fillTop && bottomViewOutsideOfScrollArea {
currentSpaceForCompare = currentSpace * 2;
}
let width = view.bounds.width let width = view.bounds.width
if !MVMCoreGetterUtility.cgfequalwiththreshold(newSpace, currentSpaceForCompare, 0.1) { if !MVMCoreGetterUtility.cgfequalwiththreshold(newSpace, currentSpace, 0.1) {
if fillTop && fillBottom { if fillTop && fillBottom {
// space both // space both
let half = newSpace / 2 let half = newSpace / 2
@ -125,10 +118,9 @@ open class ThreeLayerTableViewController: ProgrammaticTableViewController {
var topView = viewForTop() var topView = viewForTop()
self.topView = topView self.topView = topView
// If top view is outside of scroll area, create a dummy view for the header. // If top view is outside of scroll area, create a dummy view for the header. Small height is needed to stop apple from adding padding for grouped tables when no header.
if topViewOutsideOfScrollArea { if topViewOutsideOfScrollArea {
topView = MVMCoreUICommonViewsUtility.commonView() topView = MVMCoreUICommonViewsUtility.getView(with: 0.5)
topView.heightAnchor.constraint(equalToConstant: 0.5).isActive = true
} }
let headerView = MVMCoreUICommonViewsUtility.commonView() let headerView = MVMCoreUICommonViewsUtility.commonView()
headerView.addSubview(topView) headerView.addSubview(topView)
@ -146,10 +138,9 @@ open class ThreeLayerTableViewController: ProgrammaticTableViewController {
var bottomView = viewForBottom() var bottomView = viewForBottom()
self.bottomView = bottomView self.bottomView = bottomView
// If bottom view is outside of scroll area, create a dummy view for the header. // If bottom view is outside of scroll area, create a dummy view for the header. Small height is needed to stop apple from adding padding for grouped tables when no header.
if bottomViewOutsideOfScrollArea { if bottomViewOutsideOfScrollArea {
bottomView = MVMCoreUICommonViewsUtility.commonView() bottomView = MVMCoreUICommonViewsUtility.getView(with: 0.5)
bottomView.heightAnchor.constraint(equalToConstant: 0.5).isActive = true
} }
let footerView = MVMCoreUICommonViewsUtility.commonView() let footerView = MVMCoreUICommonViewsUtility.commonView()
footerView.addSubview(bottomView) footerView.addSubview(bottomView)
@ -188,7 +179,6 @@ open class ThreeLayerTableViewController: ProgrammaticTableViewController {
tableHeaderView.addSubview(headerView) tableHeaderView.addSubview(headerView)
NSLayoutConstraint.constraintPinSubview(toSuperview: headerView) NSLayoutConstraint.constraintPinSubview(toSuperview: headerView)
tableView?.tableHeaderView = tableHeaderView tableView?.tableHeaderView = tableHeaderView
} }
/// Takes the current footerView and adds it to the tableFooterView /// Takes the current footerView and adds it to the tableFooterView
@ -229,18 +219,14 @@ open class ThreeLayerTableViewController: ProgrammaticTableViewController {
//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 {
let view = MVMCoreUICommonViewsUtility.commonView()
// Small height is needed to stop apple from adding padding for grouped tables when no header. // Small height is needed to stop apple from adding padding for grouped tables when no header.
view.heightAnchor.constraint(equalToConstant: 1).isActive = true return MVMCoreUICommonViewsUtility.getView(with: 1)
return view
} }
/// Subclass for a bottom view. /// Subclass for a bottom view.
open func viewForBottom() -> UIView { open func viewForBottom() -> UIView {
// Default spacing is standard when no buttons. // Default spacing is standard when no buttons.
let view = MVMCoreUICommonViewsUtility.commonView() return MVMCoreUICommonViewsUtility.getView(with: PaddingDefaultVerticalSpacing)
view.heightAnchor.constraint(equalToConstant: PaddingDefaultVerticalSpacing).isActive = true
return view
} }
deinit { deinit {

View File

@ -20,4 +20,10 @@ public extension MVMCoreUICommonViewsUtility {
return toolbar return toolbar
} }
static func getView(with height: CGFloat) -> UIView {
let view = self.commonView()
view.heightAnchor.constraint(equalToConstant: height).isActive = true
return view
}
} }