refactored button group position layout
added in rowQuantity Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
This commit is contained in:
parent
1257112c06
commit
e3d2ca8ff2
@ -121,6 +121,7 @@ open class ButtonGroup: View, UICollectionViewDataSource, UICollectionViewDelega
|
|||||||
open override func updateView() {
|
open override func updateView() {
|
||||||
super.updateView()
|
super.updateView()
|
||||||
positionLayout.position = buttonPosition
|
positionLayout.position = buttonPosition
|
||||||
|
positionLayout.rowQuantity = rowQuantity
|
||||||
collectionView.reloadData()
|
collectionView.reloadData()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -169,8 +170,6 @@ open class ButtonGroup: View, UICollectionViewDataSource, UICollectionViewDelega
|
|||||||
public func collectionView(_ collectionView: UICollectionView, buttonableAtIndexPath indexPath: IndexPath) -> Buttonable {
|
public func collectionView(_ collectionView: UICollectionView, buttonableAtIndexPath indexPath: IndexPath) -> Buttonable {
|
||||||
buttons[indexPath.row]
|
buttons[indexPath.row]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public func collectionView(_ collectionView: UICollectionView, insetsForItemsInSection section: Int) -> UIEdgeInsets {
|
|
||||||
UIEdgeInsets.zero
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,7 +11,7 @@ import UIKit
|
|||||||
|
|
||||||
class ButtonCollectionViewRow {
|
class ButtonCollectionViewRow {
|
||||||
var attributes = [ButtonLayoutAttributes]()
|
var attributes = [ButtonLayoutAttributes]()
|
||||||
|
|
||||||
init() {}
|
init() {}
|
||||||
|
|
||||||
func add(attribute: ButtonLayoutAttributes) {
|
func add(attribute: ButtonLayoutAttributes) {
|
||||||
@ -49,9 +49,9 @@ class ButtonCollectionViewRow {
|
|||||||
case .left:
|
case .left:
|
||||||
break
|
break
|
||||||
case .center:
|
case .center:
|
||||||
offset = (collectionViewWidth - rowWidth) / 2
|
offset = (collectionViewWidth - rowWidth) / 2
|
||||||
case .right:
|
case .right:
|
||||||
offset = (collectionViewWidth - rowWidth)
|
offset = (collectionViewWidth - rowWidth)
|
||||||
}
|
}
|
||||||
|
|
||||||
for attribute in attributes {
|
for attribute in attributes {
|
||||||
@ -68,7 +68,6 @@ public enum ButtonPosition: String, CaseIterable {
|
|||||||
protocol ButtongGroupPositionLayoutDelegate: AnyObject {
|
protocol ButtongGroupPositionLayoutDelegate: AnyObject {
|
||||||
func collectionView(_ collectionView: UICollectionView, sizeForItemAtIndexPath indexPath: IndexPath) -> CGSize
|
func collectionView(_ collectionView: UICollectionView, sizeForItemAtIndexPath indexPath: IndexPath) -> CGSize
|
||||||
func collectionView(_ collectionView: UICollectionView, buttonableAtIndexPath indexPath: IndexPath) -> any Buttonable
|
func collectionView(_ collectionView: UICollectionView, buttonableAtIndexPath indexPath: IndexPath) -> any Buttonable
|
||||||
func collectionView(_ collectionView: UICollectionView, insetsForItemsInSection section: Int) -> UIEdgeInsets
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class ButtonLayoutAttributes: UICollectionViewLayoutAttributes{
|
class ButtonLayoutAttributes: UICollectionViewLayoutAttributes{
|
||||||
@ -88,6 +87,8 @@ class ButtonGroupPositionLayout: UICollectionViewLayout {
|
|||||||
// Total height of the content. Will be used to configure the scrollview content
|
// Total height of the content. Will be used to configure the scrollview content
|
||||||
var layoutHeight: CGFloat = 0.0
|
var layoutHeight: CGFloat = 0.0
|
||||||
var position: ButtonPosition = .left
|
var position: ButtonPosition = .left
|
||||||
|
var rowQuantity: Int = 0
|
||||||
|
|
||||||
private var itemCache: [ButtonLayoutAttributes] = []
|
private var itemCache: [ButtonLayoutAttributes] = []
|
||||||
|
|
||||||
override func prepare() {
|
override func prepare() {
|
||||||
@ -96,101 +97,109 @@ class ButtonGroupPositionLayout: UICollectionViewLayout {
|
|||||||
itemCache.removeAll()
|
itemCache.removeAll()
|
||||||
layoutHeight = 0.0
|
layoutHeight = 0.0
|
||||||
|
|
||||||
guard let collectionView, let delegate else {
|
guard let collectionView, let delegate else { return }
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Variable to track the width of the layout at the current state when the item is being drawn
|
// Variable to track the width of the layout at the current state when the item is being drawn
|
||||||
var layoutWidthIterator: CGFloat = 0.0
|
var layoutWidthIterator: CGFloat = 0.0
|
||||||
|
|
||||||
// Only 1 section in the ButtonGroup
|
// Only 1 section in the ButtonGroup
|
||||||
let section = 0
|
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.
|
// Variables to track individual item width and cumultative height of all items as they are being laid out.
|
||||||
var itemSize: CGSize = .zero
|
var itemSize: CGSize = .zero
|
||||||
|
|
||||||
// add top
|
// get number of buttonables
|
||||||
layoutHeight += insets.top
|
|
||||||
|
|
||||||
let totalItems = collectionView.numberOfItems(inSection: section)
|
let totalItems = collectionView.numberOfItems(inSection: section)
|
||||||
|
|
||||||
|
//create rows
|
||||||
|
var rows = [ButtonCollectionViewRow]()
|
||||||
|
rows.append(ButtonCollectionViewRow())
|
||||||
|
|
||||||
|
let collectionViewWidth = collectionView.frame.width
|
||||||
|
|
||||||
for item in 0..<totalItems {
|
for item in 0..<totalItems {
|
||||||
|
|
||||||
|
// start out with no spacing after the item
|
||||||
var itemSpacing = 0.0
|
var itemSpacing = 0.0
|
||||||
|
|
||||||
|
// create the indexPath
|
||||||
let indexPath = IndexPath(item: item, section: section)
|
let indexPath = IndexPath(item: item, section: section)
|
||||||
|
|
||||||
|
// get the rect size of the buttonable
|
||||||
itemSize = delegate.collectionView(collectionView, sizeForItemAtIndexPath: indexPath)
|
itemSize = delegate.collectionView(collectionView, sizeForItemAtIndexPath: indexPath)
|
||||||
|
|
||||||
if (layoutWidthIterator + itemSize.width + insets.left + insets.right) > collectionView.frame.width {
|
// determine if the current buttonable will fit in the row
|
||||||
// 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
|
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
|
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)
|
let itemButtonable = delegate.collectionView(collectionView, buttonableAtIndexPath: indexPath)
|
||||||
|
|
||||||
|
// see if there is another item in the array
|
||||||
let nextItem = item + 1
|
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 {
|
if nextItem < totalItems {
|
||||||
|
|
||||||
|
//get the next buttonable
|
||||||
let neighbor = delegate.collectionView(collectionView, buttonableAtIndexPath: IndexPath(item: nextItem, section: section))
|
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)
|
itemSpacing = ButtonGroupConstants.getHorizontalSpacing(for: itemButtonable, neighboring: neighbor)
|
||||||
}
|
}
|
||||||
|
|
||||||
let frame = CGRect(x: layoutWidthIterator + insets.left, y: layoutHeight, width: itemSize.width, height: itemSize.height)
|
// create the custom layout attribute
|
||||||
//print(frame)
|
|
||||||
let attributes = ButtonLayoutAttributes(spacing: itemSpacing, forCellWith: indexPath)
|
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)
|
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
|
layoutWidthIterator = 0.0
|
||||||
|
|
||||||
|
// recalculate rows x based off of positions
|
||||||
|
rows.forEach { $0.layout(for: position, with: collectionViewWidth) }
|
||||||
|
|
||||||
//Turn into rows and re-calculate
|
// calculate the
|
||||||
var rows = [ButtonCollectionViewRow]()
|
layoutHeight = 0.0
|
||||||
var currentRowY: CGFloat = -1
|
|
||||||
|
|
||||||
for attribute in itemCache {
|
// loop through the rows and set
|
||||||
if currentRowY != attribute.frame.midY {
|
// the row y position for each element
|
||||||
currentRowY = attribute.frame.midY
|
// also add to the layoutHeight
|
||||||
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
|
|
||||||
for item in 0..<rows.count {
|
for item in 0..<rows.count {
|
||||||
let row = rows[item]
|
let row = rows[item]
|
||||||
var rowSpacing = 0.0
|
var rowSpacing = 0.0
|
||||||
|
|
||||||
if item > 0 && item < rows.count {
|
|
||||||
rowSpacing = row.hasButtons ? ButtonGroupConstants.rowSpacingButton : ButtonGroupConstants.rowSpacingTextLink
|
|
||||||
}
|
|
||||||
|
|
||||||
if item > 0 {
|
if item > 0 {
|
||||||
|
rowSpacing = row.hasButtons ? ButtonGroupConstants.rowSpacingButton : ButtonGroupConstants.rowSpacingTextLink
|
||||||
row.rowY = layoutHeight + rowSpacing
|
row.rowY = layoutHeight + rowSpacing
|
||||||
layoutHeight += rowSpacing
|
layoutHeight += rowSpacing
|
||||||
}
|
}
|
||||||
|
|
||||||
layoutHeight += row.rowHeight
|
layoutHeight += row.rowHeight
|
||||||
}
|
}
|
||||||
layoutHeight += insets.bottom
|
|
||||||
|
|
||||||
|
|
||||||
|
let rowAttributes = rows.flatMap { $0.attributes }
|
||||||
itemCache = rowAttributes
|
itemCache = rowAttributes
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -227,8 +236,7 @@ class ButtonGroupPositionLayout: UICollectionViewLayout {
|
|||||||
guard let collectionView = collectionView else {
|
guard let collectionView = collectionView else {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
let insets = collectionView.contentInset
|
return collectionView.bounds.width
|
||||||
return collectionView.bounds.width - (insets.left + insets.right)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user