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:
parent
81f7341148
commit
fd8e68f1c3
@ -8,77 +8,28 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
struct ButtonGroupConstants {
|
struct ButtonGroupConstants {
|
||||||
static let rowSpacingButton = 12.0
|
static let defaultSpace = 12.0
|
||||||
static let rowSpacingTextLink = 12.0
|
|
||||||
|
enum ButtonSpacingAxis {
|
||||||
static func getHorizontalSpacing(for primary: Buttonable, neighboring: Buttonable) -> CGFloat {
|
case horizontal, vertical
|
||||||
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 func getVerticalSpacing(for primary: Buttonable, neighboring: Buttonable) -> CGFloat {
|
/// This will determine the spacing that will go between 2 buttonables either horizontally or vertically
|
||||||
let defaultSpace = 12.0
|
/// - 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
|
//large button
|
||||||
if let button = primary as? Button, button.size == .large {
|
if let button = primary as? Button, button.size == .large {
|
||||||
if let neighboringButton = neighboring as? Button, neighboringButton.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 {
|
} else if let neighboringTextLink = neighboring as? TextLink, neighboringTextLink.size == .large {
|
||||||
return 16.0
|
return axis == .horizontal ? 16.0 : 16.0
|
||||||
} else if let _ = neighboring as? TextLinkCaret {
|
|
||||||
return 24.0
|
|
||||||
} else {
|
} else {
|
||||||
return defaultSpace
|
return defaultSpace
|
||||||
}
|
}
|
||||||
@ -86,11 +37,11 @@ struct ButtonGroupConstants {
|
|||||||
//large text link
|
//large text link
|
||||||
else if let textLink = primary as? TextLink, textLink.size == .large {
|
else if let textLink = primary as? TextLink, textLink.size == .large {
|
||||||
if let neighboringButton = neighboring as? Button, neighboringButton.size == .large {
|
if let neighboringButton = neighboring as? Button, neighboringButton.size == .large {
|
||||||
return 16.0
|
return axis == .horizontal ? 16.0 : 16.0
|
||||||
} else if let _ = neighboring as? TextLinkCaret {
|
} else if neighboring is TextLinkCaret {
|
||||||
return 24.0
|
return axis == .horizontal ? 24.0 : 24.0
|
||||||
} else if let neighboringTextLink = neighboring as? TextLink, neighboringTextLink.size == .large {
|
} else if let neighboringTextLink = neighboring as? TextLink, neighboringTextLink.size == .large {
|
||||||
return 24.0
|
return axis == .horizontal ? 16.0 : 24.0
|
||||||
} else {
|
} else {
|
||||||
return defaultSpace
|
return defaultSpace
|
||||||
}
|
}
|
||||||
@ -98,11 +49,11 @@ struct ButtonGroupConstants {
|
|||||||
//text link caret
|
//text link caret
|
||||||
else if let _ = primary as? TextLinkCaret {
|
else if let _ = primary as? TextLinkCaret {
|
||||||
if let neighboringButton = neighboring as? Button, neighboringButton.size == .large {
|
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 {
|
} 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 {
|
} else if let neighboringTextLink = neighboring as? TextLink, neighboringTextLink.size == .large {
|
||||||
return 24.0
|
return axis == .horizontal ? 24.0 : 24.0
|
||||||
} else {
|
} else {
|
||||||
return defaultSpace
|
return defaultSpace
|
||||||
}
|
}
|
||||||
@ -110,9 +61,9 @@ struct ButtonGroupConstants {
|
|||||||
//small button
|
//small button
|
||||||
else if let button = primary as? Button, button.size == .small {
|
else if let button = primary as? Button, button.size == .small {
|
||||||
if let neighboringButton = neighboring as? Button, neighboringButton.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 {
|
} else if let neighboringTextLink = neighboring as? TextLink, neighboringTextLink.size == .small {
|
||||||
return 24.0
|
return axis == .horizontal ? 16.0 : 24.0
|
||||||
} else {
|
} else {
|
||||||
return defaultSpace
|
return defaultSpace
|
||||||
}
|
}
|
||||||
@ -120,9 +71,9 @@ struct ButtonGroupConstants {
|
|||||||
//small text link
|
//small text link
|
||||||
else if let textLink = primary as? TextLink, textLink.size == .small {
|
else if let textLink = primary as? TextLink, textLink.size == .small {
|
||||||
if let neighboringTextLink = neighboring as? TextLink, neighboringTextLink.size == .small {
|
if let neighboringTextLink = neighboring as? TextLink, neighboringTextLink.size == .small {
|
||||||
return 32.0
|
return axis == .horizontal ? 16.0 : 24.0
|
||||||
} else if let neighboringButton = neighboring as? Button, neighboringButton.size == .small {
|
} else if let _ = neighboring as? Button {
|
||||||
return 24.0
|
return axis == .horizontal ? 16.0 : 32.0
|
||||||
} else {
|
} else {
|
||||||
return defaultSpace
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,7 +17,7 @@ class ButtonCollectionViewRow {
|
|||||||
func add(attribute: ButtonLayoutAttributes) {
|
func add(attribute: ButtonLayoutAttributes) {
|
||||||
attributes.append(attribute)
|
attributes.append(attribute)
|
||||||
}
|
}
|
||||||
|
|
||||||
var hasButtons: Bool {
|
var hasButtons: Bool {
|
||||||
attributes.contains(where: { $0.isButton })
|
attributes.contains(where: { $0.isButton })
|
||||||
}
|
}
|
||||||
@ -33,7 +33,7 @@ class ButtonCollectionViewRow {
|
|||||||
var rowHeight: CGFloat {
|
var rowHeight: CGFloat {
|
||||||
attributes.compactMap{$0.frame.height}.max() ?? 0
|
attributes.compactMap{$0.frame.height}.max() ?? 0
|
||||||
}
|
}
|
||||||
|
|
||||||
var maxHeightIndexPath: IndexPath {
|
var maxHeightIndexPath: IndexPath {
|
||||||
let maxHeight = rowHeight
|
let maxHeight = rowHeight
|
||||||
return attributes.first(where: {$0.frame.height == maxHeight})!.indexPath
|
return attributes.first(where: {$0.frame.height == maxHeight})!.indexPath
|
||||||
@ -112,7 +112,8 @@ class ButtonCollectionViewRow {
|
|||||||
for attribute in attributes {
|
for attribute in attributes {
|
||||||
attribute.frame.origin.x = offset
|
attribute.frame.origin.x = offset
|
||||||
if attribute.frame.height < height {
|
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
|
offset += attribute.frame.width + attribute.spacing
|
||||||
}
|
}
|
||||||
@ -130,11 +131,20 @@ protocol ButtongGroupPositionLayoutDelegate: AnyObject {
|
|||||||
|
|
||||||
class ButtonLayoutAttributes: UICollectionViewLayoutAttributes{
|
class ButtonLayoutAttributes: UICollectionViewLayoutAttributes{
|
||||||
var spacing: CGFloat = 0
|
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,
|
convenience init(spacing: CGFloat,
|
||||||
|
buttonable: Buttonable,
|
||||||
forCellWith indexPath: IndexPath) {
|
forCellWith indexPath: IndexPath) {
|
||||||
self.init(forCellWith: indexPath)
|
self.init(forCellWith: indexPath)
|
||||||
self.spacing = spacing
|
self.spacing = spacing
|
||||||
|
self.buttonable = buttonable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -218,13 +228,12 @@ class ButtonGroupPositionLayout: UICollectionViewLayout {
|
|||||||
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
|
// 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
|
// 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.frame = CGRect(x: 0, y: 0, width: itemSize.width, height: itemSize.height)
|
||||||
attributes.isButton = isButton(buttonable: itemButtonable)
|
|
||||||
|
|
||||||
// add it to the array
|
// add it to the array
|
||||||
rows.last?.add(attribute: attributes)
|
rows.last?.add(attribute: attributes)
|
||||||
@ -247,7 +256,8 @@ class ButtonGroupPositionLayout: UICollectionViewLayout {
|
|||||||
var rowSpacing = 0.0
|
var rowSpacing = 0.0
|
||||||
|
|
||||||
if item > 0 {
|
if item > 0 {
|
||||||
rowSpacing = 12.0
|
let prevRow = rows[item - 1]
|
||||||
|
rowSpacing = ButtonGroupConstants.getVerticalSpacing(for: prevRow, neighboringRow: row)
|
||||||
row.rowY = layoutHeight + rowSpacing
|
row.rowY = layoutHeight + rowSpacing
|
||||||
layoutHeight += rowSpacing
|
layoutHeight += rowSpacing
|
||||||
}
|
}
|
||||||
@ -265,14 +275,6 @@ class ButtonGroupPositionLayout: UICollectionViewLayout {
|
|||||||
itemCache = rowAttributes
|
itemCache = rowAttributes
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func isButton(buttonable: Buttonable) -> Bool{
|
|
||||||
if let _ = buttonable as? Button {
|
|
||||||
return true
|
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override func layoutAttributesForElements(in rect: CGRect)-> [UICollectionViewLayoutAttributes]? {
|
override func layoutAttributesForElements(in rect: CGRect)-> [UICollectionViewLayoutAttributes]? {
|
||||||
var visibleLayoutAttributes: [UICollectionViewLayoutAttributes] = []
|
var visibleLayoutAttributes: [UICollectionViewLayoutAttributes] = []
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user