From e3d2ca8ff290ad7ceccb28574fbe108ae269f919 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Thu, 1 Dec 2022 15:15:21 -0600 Subject: [PATCH] refactored button group position layout added in rowQuantity Signed-off-by: Matt Bruce --- .../Buttons/ButtonGroup/ButtonGroup.swift | 5 +- .../ButtonGroupPositionLayout.swift | 114 ++++++++++-------- 2 files changed, 63 insertions(+), 56 deletions(-) diff --git a/VDS/Components/Buttons/ButtonGroup/ButtonGroup.swift b/VDS/Components/Buttons/ButtonGroup/ButtonGroup.swift index 28ddebd3..cc7c54f4 100644 --- a/VDS/Components/Buttons/ButtonGroup/ButtonGroup.swift +++ b/VDS/Components/Buttons/ButtonGroup/ButtonGroup.swift @@ -121,6 +121,7 @@ open class ButtonGroup: View, UICollectionViewDataSource, UICollectionViewDelega open override func updateView() { super.updateView() positionLayout.position = buttonPosition + positionLayout.rowQuantity = rowQuantity collectionView.reloadData() } @@ -169,8 +170,6 @@ open class ButtonGroup: View, UICollectionViewDataSource, UICollectionViewDelega public func collectionView(_ collectionView: UICollectionView, buttonableAtIndexPath indexPath: IndexPath) -> Buttonable { buttons[indexPath.row] } + - public func collectionView(_ collectionView: UICollectionView, insetsForItemsInSection section: Int) -> UIEdgeInsets { - UIEdgeInsets.zero - } } diff --git a/VDS/Components/Buttons/ButtonGroup/ButtonGroupPositionLayout.swift b/VDS/Components/Buttons/ButtonGroup/ButtonGroupPositionLayout.swift index a6ad235a..32bdab7b 100644 --- a/VDS/Components/Buttons/ButtonGroup/ButtonGroupPositionLayout.swift +++ b/VDS/Components/Buttons/ButtonGroup/ButtonGroupPositionLayout.swift @@ -11,7 +11,7 @@ import UIKit class ButtonCollectionViewRow { var attributes = [ButtonLayoutAttributes]() - + init() {} func add(attribute: ButtonLayoutAttributes) { @@ -49,9 +49,9 @@ class ButtonCollectionViewRow { case .left: break case .center: - offset = (collectionViewWidth - rowWidth) / 2 + offset = (collectionViewWidth - rowWidth) / 2 case .right: - offset = (collectionViewWidth - rowWidth) + offset = (collectionViewWidth - rowWidth) } for attribute in attributes { @@ -68,7 +68,6 @@ public enum ButtonPosition: String, CaseIterable { protocol ButtongGroupPositionLayoutDelegate: AnyObject { func collectionView(_ collectionView: UICollectionView, sizeForItemAtIndexPath indexPath: IndexPath) -> CGSize func collectionView(_ collectionView: UICollectionView, buttonableAtIndexPath indexPath: IndexPath) -> any Buttonable - func collectionView(_ collectionView: UICollectionView, insetsForItemsInSection section: Int) -> UIEdgeInsets } class ButtonLayoutAttributes: UICollectionViewLayoutAttributes{ @@ -88,6 +87,8 @@ class ButtonGroupPositionLayout: UICollectionViewLayout { // Total height of the content. Will be used to configure the scrollview content var layoutHeight: CGFloat = 0.0 var position: ButtonPosition = .left + var rowQuantity: Int = 0 + private var itemCache: [ButtonLayoutAttributes] = [] override func prepare() { @@ -96,101 +97,109 @@ class ButtonGroupPositionLayout: UICollectionViewLayout { itemCache.removeAll() layoutHeight = 0.0 - guard let collectionView, let delegate else { - return - } - + guard let collectionView, let delegate else { return } // Variable to track the width of the layout at the current state when the item is being drawn var layoutWidthIterator: CGFloat = 0.0 // Only 1 section in the ButtonGroup let section = 0 - - // Get the necessary data (if implemented) from the delegates else provide default values - let insets: UIEdgeInsets = delegate.collectionView(collectionView, insetsForItemsInSection: section) - - let rowSpacing: CGFloat = ButtonGroupConstants.rowSpacingButton - + // Variables to track individual item width and cumultative height of all items as they are being laid out. var itemSize: CGSize = .zero - - // add top - layoutHeight += insets.top - + + // get number of buttonables let totalItems = collectionView.numberOfItems(inSection: section) + + //create rows + var rows = [ButtonCollectionViewRow]() + rows.append(ButtonCollectionViewRow()) + + let collectionViewWidth = collectionView.frame.width + for item in 0.. collectionView.frame.width { - // If the current row width (after this item being laid out) is exceeding the width of the collection view content, put it in the next line + // determine if the current buttonable will fit in the row + let rowItemCount = rows.last?.attributes.count ?? 0 + + if (layoutWidthIterator + itemSize.width) > collectionViewWidth || (rowQuantity > 0 && rowItemCount == rowQuantity) { + + // If the current row width (after this item being laid out) is exceeding + // the width of the collection view content, put it in the next line layoutWidthIterator = 0.0 - layoutHeight += itemSize.height + rowSpacing + + // set the spacing of the last item of the current row to 0 + rows.last?.attributes.last?.spacing = 0 + + // add a new row + rows.append(ButtonCollectionViewRow()) } + // get the buttonable let itemButtonable = delegate.collectionView(collectionView, buttonableAtIndexPath: indexPath) + // see if there is another item in the array let nextItem = item + 1 + + // if so, get the buttonable + // and get the spacing based of the + // current buttonable and the next buttonable if nextItem < totalItems { + + //get the next buttonable let neighbor = delegate.collectionView(collectionView, buttonableAtIndexPath: IndexPath(item: nextItem, section: section)) + + // get the spacing to go between the current and next buttonable itemSpacing = ButtonGroupConstants.getHorizontalSpacing(for: itemButtonable, neighboring: neighbor) } - let frame = CGRect(x: layoutWidthIterator + insets.left, y: layoutHeight, width: itemSize.width, height: itemSize.height) - //print(frame) + // create the custom layout attribute let attributes = ButtonLayoutAttributes(spacing: itemSpacing, forCellWith: indexPath) - attributes.frame = frame + attributes.frame = CGRect(x: 0, y: 0, width: itemSize.width, height: itemSize.height) attributes.isButton = isButton(buttonable: itemButtonable) - itemCache.append(attributes) - layoutWidthIterator = layoutWidthIterator + frame.width + itemSpacing + // add it to the array + rows.last?.add(attribute: attributes) + + // update the current width + // add the current frame width + the found spacing + layoutWidthIterator = layoutWidthIterator + attributes.frame.width + itemSpacing } - //add bottom - layoutHeight += itemSize.height + insets.bottom layoutWidthIterator = 0.0 + // recalculate rows x based off of positions + rows.forEach { $0.layout(for: position, with: collectionViewWidth) } - //Turn into rows and re-calculate - var rows = [ButtonCollectionViewRow]() - var currentRowY: CGFloat = -1 + // calculate the + layoutHeight = 0.0 - for attribute in itemCache { - if currentRowY != attribute.frame.midY { - currentRowY = attribute.frame.midY - rows.append(ButtonCollectionViewRow()) - } - rows.last?.add(attribute: attribute) - } - - //recalculate rows based off of positions - rows.forEach { $0.layout(for: position, with: collectionView.frame.width) } - let rowAttributes = rows.flatMap { $0.attributes } - - layoutHeight = insets.top + // loop through the rows and set + // the row y position for each element + // also add to the layoutHeight for item in 0.. 0 && item < rows.count { - rowSpacing = row.hasButtons ? ButtonGroupConstants.rowSpacingButton : ButtonGroupConstants.rowSpacingTextLink - } - + if item > 0 { + rowSpacing = row.hasButtons ? ButtonGroupConstants.rowSpacingButton : ButtonGroupConstants.rowSpacingTextLink row.rowY = layoutHeight + rowSpacing layoutHeight += rowSpacing } layoutHeight += row.rowHeight } - layoutHeight += insets.bottom - + let rowAttributes = rows.flatMap { $0.attributes } itemCache = rowAttributes } @@ -227,8 +236,7 @@ class ButtonGroupPositionLayout: UICollectionViewLayout { guard let collectionView = collectionView else { return 0 } - let insets = collectionView.contentInset - return collectionView.bounds.width - (insets.left + insets.right) + return collectionView.bounds.width } }