refactored spacing algos since we are now not resizing rectangle heights based off of the tallest container in the row

Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
This commit is contained in:
Matt Bruce 2022-12-15 11:48:14 -06:00
parent 81f7341148
commit fd8e68f1c3
2 changed files with 96 additions and 93 deletions

View File

@ -8,77 +8,28 @@
import Foundation
struct ButtonGroupConstants {
static let rowSpacingButton = 12.0
static let rowSpacingTextLink = 12.0
static func getHorizontalSpacing(for primary: Buttonable, neighboring: Buttonable) -> CGFloat {
let defaultSpace = 12.0
//large button
if let button = primary as? Button, button.size == .large {
if let neighboringButton = neighboring as? Button, neighboringButton.size == .large {
return 12.0
} else if let neighboringTextLink = neighboring as? TextLink, neighboringTextLink.size == .large {
return 16.0
} else if let _ = neighboring as? TextLinkCaret {
return 24.0
} else {
return defaultSpace
}
}
//large text link
else if let textLink = primary as? TextLink, textLink.size == .large {
if let neighboringButton = neighboring as? Button, neighboringButton.size == .large {
return 16.0
} else if let _ = neighboring as? TextLinkCaret {
return 24.0
} else if let neighboringTextLink = neighboring as? TextLink, neighboringTextLink.size == .large {
return 16.0
} else {
return defaultSpace
}
}
//text link caret
else if let _ = primary as? TextLinkCaret {
if let _ = neighboring as? TextLinkCaret {
return 24.0
} else {
return defaultSpace
}
}
//small button
else if let button = primary as? Button, button.size == .small {
if let neighboringButton = neighboring as? Button, neighboringButton.size == .small {
return 12.0
} else if let neighboringTextLink = neighboring as? TextLink, neighboringTextLink.size == .small {
return 16.0
} else {
return defaultSpace
}
}
//small text link
else if let textLink = primary as? TextLink, textLink.size == .small {
if let neighboringTextLink = neighboring as? TextLink, neighboringTextLink.size == .small {
return 16.0
} else {
return defaultSpace
}
}
//return defaultSpace
else {
return defaultSpace
}
static let defaultSpace = 12.0
enum ButtonSpacingAxis {
case horizontal, vertical
}
static func getVerticalSpacing(for primary: Buttonable, neighboring: Buttonable) -> CGFloat {
let defaultSpace = 12.0
/// This will determine the spacing that will go between 2 buttonables either horizontally or vertically
/// - Parameters:
/// - axis: horizontal/vertical
/// - primary: first buttonable
/// - neighboring: next buttonable based off of axis
/// - Returns: float value
static func getSpacing(for axis: ButtonSpacingAxis, with primary: Buttonable, neighboring: Buttonable) -> CGFloat {
//large button
if let button = primary as? Button, button.size == .large {
if let neighboringButton = neighboring as? Button, neighboringButton.size == .large {
return 12.0
return axis == .horizontal ? 12.0 : 12.0
} else if neighboring is TextLinkCaret {
return axis == .horizontal ? 24.0 : 24.0
} else if let neighboringTextLink = neighboring as? TextLink, neighboringTextLink.size == .large {
return 16.0
} else if let _ = neighboring as? TextLinkCaret {
return 24.0
return axis == .horizontal ? 16.0 : 16.0
} else {
return defaultSpace
}
@ -86,11 +37,11 @@ struct ButtonGroupConstants {
//large text link
else if let textLink = primary as? TextLink, textLink.size == .large {
if let neighboringButton = neighboring as? Button, neighboringButton.size == .large {
return 16.0
} else if let _ = neighboring as? TextLinkCaret {
return 24.0
return axis == .horizontal ? 16.0 : 16.0
} else if neighboring is TextLinkCaret {
return axis == .horizontal ? 24.0 : 24.0
} else if let neighboringTextLink = neighboring as? TextLink, neighboringTextLink.size == .large {
return 24.0
return axis == .horizontal ? 16.0 : 24.0
} else {
return defaultSpace
}
@ -98,11 +49,11 @@ struct ButtonGroupConstants {
//text link caret
else if let _ = primary as? TextLinkCaret {
if let neighboringButton = neighboring as? Button, neighboringButton.size == .large {
return 16.0
return axis == .horizontal ? 24.0 : 24.0
} else if let _ = neighboring as? TextLinkCaret {
return 24.0
return axis == .horizontal ? 24.0 : 24.0
} else if let neighboringTextLink = neighboring as? TextLink, neighboringTextLink.size == .large {
return 24.0
return axis == .horizontal ? 24.0 : 24.0
} else {
return defaultSpace
}
@ -110,9 +61,9 @@ struct ButtonGroupConstants {
//small button
else if let button = primary as? Button, button.size == .small {
if let neighboringButton = neighboring as? Button, neighboringButton.size == .small {
return 12.0
return axis == .horizontal ? 12.0 : 12.0
} else if let neighboringTextLink = neighboring as? TextLink, neighboringTextLink.size == .small {
return 24.0
return axis == .horizontal ? 16.0 : 24.0
} else {
return defaultSpace
}
@ -120,9 +71,9 @@ struct ButtonGroupConstants {
//small text link
else if let textLink = primary as? TextLink, textLink.size == .small {
if let neighboringTextLink = neighboring as? TextLink, neighboringTextLink.size == .small {
return 32.0
} else if let neighboringButton = neighboring as? Button, neighboringButton.size == .small {
return 24.0
return axis == .horizontal ? 16.0 : 24.0
} else if let _ = neighboring as? Button {
return axis == .horizontal ? 16.0 : 32.0
} else {
return defaultSpace
}
@ -133,4 +84,54 @@ struct ButtonGroupConstants {
}
}
//
/// Gets the tallest buttonables within the row
/// - Parameter row: Row that includes the attributes
/// - Returns: Array of [ButtonLayoutAttributes] of the tallest items
private static func getTallestAttributes(for row: ButtonCollectionViewRow) -> [ButtonLayoutAttributes] {
var height = 0.0
var foundIndexes:[Int] = []
for (index, attribute) in row.attributes.enumerated() {
if attribute.frame.height >= height {
height = attribute.frame.height
foundIndexes.append(index)
}
}
return foundIndexes.compactMap { row.attributes[$0] }
}
/// Gets the vertical spacing that will go between rows.
/// - Parameters:
/// - row: Primary row that the space will go between
/// - neighboringRow: Secondary row that will be below the Primary
/// - Returns: Amount of space that should live between these rows based off of the items. The largest space will win when the comparison occurs.
static func getVerticalSpacing(for row: ButtonCollectionViewRow, neighboringRow: ButtonCollectionViewRow?) -> CGFloat {
// if the neighboringRow is nil, this is the last row in the collection
// so return no space
guard let neighboringRow else { return 0.0 }
let primaryTallestAttributes = getTallestAttributes(for: row)
let neighboringTallestAttributes = getTallestAttributes(for: neighboringRow)
if primaryTallestAttributes.count > 0 && neighboringTallestAttributes.count > 0 {
// If there is a tie for tallest child, the tiebreaker criteria is to refer to the child with the larger space requirement (for vertical spacing).
var largestVerticalSpace = defaultSpace
primaryTallestAttributes.forEach { primaryAttribute in
neighboringTallestAttributes.forEach { neighboringTallestAttribute in
let space = getSpacing(for: .vertical, with: primaryAttribute.buttonable!, neighboring: neighboringTallestAttribute.buttonable!)
if space > largestVerticalSpace {
largestVerticalSpace = space
}
}
}
return largestVerticalSpace
}
else {
return defaultSpace
}
}
}

View File

@ -17,7 +17,7 @@ class ButtonCollectionViewRow {
func add(attribute: ButtonLayoutAttributes) {
attributes.append(attribute)
}
var hasButtons: Bool {
attributes.contains(where: { $0.isButton })
}
@ -33,7 +33,7 @@ class ButtonCollectionViewRow {
var rowHeight: CGFloat {
attributes.compactMap{$0.frame.height}.max() ?? 0
}
var maxHeightIndexPath: IndexPath {
let maxHeight = rowHeight
return attributes.first(where: {$0.frame.height == maxHeight})!.indexPath
@ -112,7 +112,8 @@ class ButtonCollectionViewRow {
for attribute in attributes {
attribute.frame.origin.x = offset
if attribute.frame.height < height {
attribute.frame.size.height = height
//recalibrate the y to vertically center align rect
attribute.frame.origin.y += (height - attribute.frame.size.height) / 2
}
offset += attribute.frame.width + attribute.spacing
}
@ -130,11 +131,20 @@ protocol ButtongGroupPositionLayoutDelegate: AnyObject {
class ButtonLayoutAttributes: UICollectionViewLayoutAttributes{
var spacing: CGFloat = 0
var isButton: Bool = false
var buttonable: Buttonable?
var isButton: Bool {
guard buttonable is Button else { return false }
return true
}
convenience init(spacing: CGFloat,
buttonable: Buttonable,
forCellWith indexPath: IndexPath) {
self.init(forCellWith: indexPath)
self.spacing = spacing
self.buttonable = buttonable
}
}
@ -218,13 +228,12 @@ class ButtonGroupPositionLayout: UICollectionViewLayout {
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.getSpacing(for: .horizontal, with: itemButtonable, neighboring: neighbor)
}
// create the custom layout attribute
let attributes = ButtonLayoutAttributes(spacing: itemSpacing, forCellWith: indexPath)
let attributes = ButtonLayoutAttributes(spacing: itemSpacing, buttonable: itemButtonable, forCellWith: indexPath)
attributes.frame = CGRect(x: 0, y: 0, width: itemSize.width, height: itemSize.height)
attributes.isButton = isButton(buttonable: itemButtonable)
// add it to the array
rows.last?.add(attribute: attributes)
@ -247,7 +256,8 @@ class ButtonGroupPositionLayout: UICollectionViewLayout {
var rowSpacing = 0.0
if item > 0 {
rowSpacing = 12.0
let prevRow = rows[item - 1]
rowSpacing = ButtonGroupConstants.getVerticalSpacing(for: prevRow, neighboringRow: row)
row.rowY = layoutHeight + rowSpacing
layoutHeight += rowSpacing
}
@ -265,14 +275,6 @@ class ButtonGroupPositionLayout: UICollectionViewLayout {
itemCache = rowAttributes
}
func isButton(buttonable: Buttonable) -> Bool{
if let _ = buttonable as? Button {
return true
} else {
return false
}
}
override func layoutAttributesForElements(in rect: CGRect)-> [UICollectionViewLayoutAttributes]? {
var visibleLayoutAttributes: [UICollectionViewLayoutAttributes] = []