three layer collection anchoring

This commit is contained in:
Pfeil, Scott Robert 2020-04-22 16:33:13 -04:00
parent e0d17f7270
commit a97132c897
4 changed files with 50 additions and 17 deletions

View File

@ -79,6 +79,8 @@ import Foundation
open override func handleNewData() {
topViewOutsideOfScrollArea = templateModel?.anchorHeader ?? false
bottomViewOutsideOfScrollArea = templateModel?.anchorFooter ?? false
setup()
registerCells()
super.handleNewData()

View File

@ -12,6 +12,8 @@ import Foundation
@objc open class ProgrammaticCollectionViewController: ScrollingViewController {
public var collectionView: UICollectionView?
public var topConstraint: NSLayoutConstraint?
public var bottomConstraint: NSLayoutConstraint?
open override func loadView() {
let view = UIView()
@ -19,7 +21,9 @@ import Foundation
let collection = createCollectionView()
view.addSubview(collection)
NSLayoutConstraint.constraintPinSubview(toSuperview: collection)
let constraints = NSLayoutConstraint.constraintPinSubview(toSuperview: collection)
topConstraint = constraints?[ConstraintTop] as? NSLayoutConstraint
bottomConstraint = constraints?[ConstraintBot] as? NSLayoutConstraint
collectionView = collection
scrollView = collectionView

View File

@ -52,16 +52,34 @@ import Foundation
footerView?.topConstraint?.constant = half
collectionView?.collectionViewLayout.invalidateLayout()
} 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.
headerView?.bottomConstraint?.constant = newSpace
collectionView?.collectionViewLayout.invalidateLayout()
} else if fillBottom {
// Only bottom is spaced.
footerView?.topConstraint?.constant = newSpace
collectionView?.collectionViewLayout.invalidateLayout()
collectionView.collectionViewLayout.invalidateLayout()
}
}
}
func addTopViewOutside() {
guard let collectionView = collectionView, let topView = topView else { return }
view.addSubview(topView)
topView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
topView.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leftAnchor).isActive = true
view.safeAreaLayoutGuide.rightAnchor.constraint(equalTo: topView.rightAnchor).isActive = true
collectionView.topAnchor.constraint(equalTo: topView.bottomAnchor).isActive = true
}
func addBottomViewOutside() {
guard let collectionView = collectionView, let bottomView = bottomView else { return }
view.addSubview(bottomView)
bottomView.topAnchor.constraint(equalTo: collectionView.bottomAnchor).isActive = true
bottomView.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leftAnchor).isActive = true
view.safeAreaLayoutGuide.rightAnchor.constraint(equalTo: bottomView.rightAnchor).isActive = true
view.safeAreaLayoutGuide.bottomAnchor.constraint(equalTo: bottomView.bottomAnchor).isActive = true
}
//MARK: - ViewController
open override func updateViews() {
@ -86,8 +104,22 @@ import Foundation
open override func handleNewData() {
super.handleNewData()
topView?.removeFromSuperview()
bottomView?.removeFromSuperview()
topView = viewForTop()
bottomView = viewForBottom()
if topViewOutsideOfScrollArea {
topConstraint?.isActive = false
addTopViewOutside()
} else {
topConstraint?.isActive = true
}
if bottomViewOutsideOfScrollArea {
bottomConstraint?.isActive = false
addBottomViewOutside()
} else {
bottomConstraint?.isActive = true
}
reloadCollectionData()
}
@ -176,14 +208,14 @@ import Foundation
open func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
if kind == UICollectionView.elementKindSectionFooter,
let footerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: footerID, for: indexPath) as? ContainerCollectionReusableView {
let bottomView = self.bottomView ?? MVMCoreUICommonViewsUtility.getView(with: 0)
let bottomView = (bottomViewOutsideOfScrollArea ? nil : self.bottomView) ?? MVMCoreUICommonViewsUtility.getView(with: 0.5)
footerView.addAndContain(view: bottomView)
footerView.topConstraint?.constant = spaceAboveBottomView() ?? 0
self.footerView = footerView
return footerView
} else if kind == UICollectionView.elementKindSectionHeader,
let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: headerID, for: indexPath) as? ContainerCollectionReusableView {
let topView = self.topView ?? MVMCoreUICommonViewsUtility.getView(with: 0)
let topView = (topViewOutsideOfScrollArea ? nil : self.topView) ?? MVMCoreUICommonViewsUtility.getView(with: 0.5)
headerView.addAndContain(view: topView)
headerView.bottomConstraint?.constant = spaceBelowTopView() ?? 0
self.headerView = headerView

View File

@ -117,22 +117,20 @@ extension ThreeLayerViewController {
if let topView = viewForTop() {
self.topView = topView
} else {
topView = MVMCoreUICommonViewsUtility.commonView()
topView?.heightAnchor.constraint(equalToConstant: 0).isActive = true
topView = MVMCoreUICommonViewsUtility.getView(with: 0)
}
guard var topView = topView else { return nil }
// Adds the top view outside the scroll if directed.
if topViewOutsideOfScroll {
topConstraint?.isActive = false;
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
topView = MVMCoreUICommonViewsUtility.getView(with: 0)
addViewInsideOfScrollViewTop(topView)
} else {
topConstraint?.isActive = true;
topConstraint?.isActive = true
addViewInsideOfScrollViewTop(topView)
}
return topView
@ -142,8 +140,7 @@ extension ThreeLayerViewController {
if let middleView = viewForMiddle() {
self.middleView = middleView
} else {
middleView = MVMCoreUICommonViewsUtility.commonView()
middleView?.heightAnchor.constraint(equalToConstant: 0).isActive = true
middleView = MVMCoreUICommonViewsUtility.getView(with: 0)
}
guard let middleView = middleView, let contentView = contentView else { return nil }
contentView.addSubview(middleView)
@ -157,8 +154,7 @@ extension ThreeLayerViewController {
if let bottomView = viewForBottom() {
self.bottomView = bottomView
} else {
bottomView = MVMCoreUICommonViewsUtility.commonView()
bottomView?.heightAnchor.constraint(equalToConstant: 0).isActive = true
bottomView = MVMCoreUICommonViewsUtility.getView(with: 0)
}
guard var bottomView = bottomView else { return nil }
@ -168,8 +164,7 @@ extension ThreeLayerViewController {
addViewOutsideOfScrollViewBottom(bottomView)
// Adds and returns an empty view to use for the internal logic.
bottomView = MVMCoreUICommonViewsUtility.commonView()
bottomView.heightAnchor.constraint(equalToConstant: 0).isActive = true
bottomView = MVMCoreUICommonViewsUtility.getView(with: 0)
addViewInsideOfScrollViewBottom(bottomView)
} else {
bottomConstraint?.isActive = true;