Merge branch 'feature/buttonGroupUpdate' of https://gitlab.verizon.com/BPHV_MIPS/vds_ios.git into feature/textLink
# Conflicts: # VDS/Components/Buttons/TextLink/TextLink.swift # VDS/Components/Buttons/TextLinkCaret/TextLinkCaret.swift Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
This commit is contained in:
commit
6880d25f2b
@ -8,6 +8,7 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
|
@objc(VDSSelfSizingCollectionView)
|
||||||
public final class SelfSizingCollectionView: UICollectionView {
|
public final class SelfSizingCollectionView: UICollectionView {
|
||||||
|
|
||||||
private var contentSizeObservation: NSKeyValueObservation?
|
private var contentSizeObservation: NSKeyValueObservation?
|
||||||
|
|||||||
@ -149,6 +149,8 @@ open class ButtonGroup: View, UICollectionViewDataSource, UICollectionViewDelega
|
|||||||
cell.subviews.forEach { $0.removeFromSuperview() }
|
cell.subviews.forEach { $0.removeFromSuperview() }
|
||||||
cell.addSubview(button)
|
cell.addSubview(button)
|
||||||
button.pinToSuperView()
|
button.pinToSuperView()
|
||||||
|
// cell.layer.borderColor = UIColor.black.cgColor
|
||||||
|
// cell.layer.borderWidth = 1
|
||||||
return cell
|
return cell
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,11 +158,19 @@ open class ButtonGroup: View, UICollectionViewDataSource, UICollectionViewDelega
|
|||||||
buttons[indexPath.row].intrinsicContentSize
|
buttons[indexPath.row].intrinsicContentSize
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func collectionView(_ collectionView: UICollectionView, isButtonTypeForItemAtIndexPath indexPath: IndexPath) -> Bool {
|
||||||
|
if let _ = buttons[indexPath.row] as? Button {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func collectionView(_ collectionView: UICollectionView, buttonableAtIndexPath indexPath: IndexPath) -> Buttonable {
|
||||||
|
buttons[indexPath.row]
|
||||||
|
}
|
||||||
|
|
||||||
public func collectionView(_ collectionView: UICollectionView, insetsForItemsInSection section: Int) -> UIEdgeInsets {
|
public func collectionView(_ collectionView: UICollectionView, insetsForItemsInSection section: Int) -> UIEdgeInsets {
|
||||||
UIEdgeInsets.zero
|
UIEdgeInsets.zero
|
||||||
}
|
}
|
||||||
|
|
||||||
public func collectionView(_ collectionView: UICollectionView, itemSpacingInSection section: Int) -> CGFloat {
|
|
||||||
itemSpacing
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,27 +8,55 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
|
class ButtonLayoutAttributes: UICollectionViewLayoutAttributes{
|
||||||
|
var spacing: CGFloat = 0
|
||||||
|
var isButton: Bool = false
|
||||||
|
convenience init(spacing: CGFloat,
|
||||||
|
forCellWith indexPath: IndexPath) {
|
||||||
|
self.init(forCellWith: indexPath)
|
||||||
|
self.spacing = spacing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class ButtonCollectionViewRow {
|
class ButtonCollectionViewRow {
|
||||||
var attributes = [UICollectionViewLayoutAttributes]()
|
var attributes = [ButtonLayoutAttributes]()
|
||||||
var spacing: CGFloat = 0
|
var spacing: CGFloat = 0
|
||||||
|
|
||||||
init(spacing: CGFloat) {
|
init(spacing: CGFloat) {
|
||||||
self.spacing = spacing
|
self.spacing = spacing
|
||||||
}
|
}
|
||||||
|
|
||||||
func add(attribute: UICollectionViewLayoutAttributes) {
|
func add(attribute: ButtonLayoutAttributes) {
|
||||||
attributes.append(attribute)
|
attributes.append(attribute)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var hasButtons: Bool {
|
||||||
|
attributes.contains(where: { $0.isButton })
|
||||||
|
}
|
||||||
|
|
||||||
var rowWidth: CGFloat {
|
var rowWidth: CGFloat {
|
||||||
return attributes.reduce(0, { result, attribute -> CGFloat in
|
return attributes.reduce(0, { result, attribute -> CGFloat in
|
||||||
return result + attribute.frame.width
|
return result + attribute.frame.width + attribute.spacing
|
||||||
}) + CGFloat(attributes.count - 1) * spacing
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var rowHeight: CGFloat {
|
||||||
|
attributes.compactMap{$0.frame.height}.max() ?? 0
|
||||||
|
}
|
||||||
|
|
||||||
|
var rowY: CGFloat = 0 {
|
||||||
|
didSet {
|
||||||
|
for attribute in attributes {
|
||||||
|
attribute.frame.origin.y = rowY
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func layout(for position: ButtonPosition, with collectionViewWidth: CGFloat){
|
func layout(for position: ButtonPosition, with collectionViewWidth: CGFloat){
|
||||||
var offset = 0.0
|
var offset = 0.0
|
||||||
|
|
||||||
|
attributes.last?.spacing = 0
|
||||||
|
|
||||||
switch position {
|
switch position {
|
||||||
case .left:
|
case .left:
|
||||||
break
|
break
|
||||||
@ -40,7 +68,7 @@ class ButtonCollectionViewRow {
|
|||||||
|
|
||||||
for attribute in attributes {
|
for attribute in attributes {
|
||||||
attribute.frame.origin.x = offset
|
attribute.frame.origin.x = offset
|
||||||
offset += attribute.frame.width + spacing
|
offset += attribute.frame.width + attribute.spacing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -51,8 +79,8 @@ 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, insetsForItemsInSection section: Int) -> UIEdgeInsets
|
func collectionView(_ collectionView: UICollectionView, insetsForItemsInSection section: Int) -> UIEdgeInsets
|
||||||
func collectionView(_ collectionView: UICollectionView, itemSpacingInSection section: Int) -> CGFloat
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class ButtonGroupPositionLayout: UICollectionViewLayout {
|
class ButtonGroupPositionLayout: UICollectionViewLayout {
|
||||||
@ -62,58 +90,74 @@ 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
|
||||||
private var itemCache: [UICollectionViewLayoutAttributes] = []
|
private var itemCache: [ButtonLayoutAttributes] = []
|
||||||
|
|
||||||
override func prepare() {
|
override func prepare() {
|
||||||
super.prepare()
|
super.prepare()
|
||||||
|
|
||||||
|
let rowSpacingButton = 12.0
|
||||||
|
let rowSpacingTextLink = 12.0
|
||||||
|
|
||||||
itemCache.removeAll()
|
itemCache.removeAll()
|
||||||
layoutHeight = 0.0
|
layoutHeight = 0.0
|
||||||
|
|
||||||
guard let collectionView = collectionView else {
|
guard let collectionView, let delegate else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var itemSpacing = 0.0
|
var itemSpacing = 0.0
|
||||||
// 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
|
||||||
|
|
||||||
for section in 0..<collectionView.numberOfSections {
|
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 = rowSpacingButton
|
||||||
|
// Variables to track individual item width and cumultative height of all items as they are being laid out.
|
||||||
|
var itemSize: CGSize = .zero
|
||||||
|
|
||||||
|
layoutHeight += insets.top
|
||||||
|
let totalItems = collectionView.numberOfItems(inSection: section)
|
||||||
|
for item in 0..<totalItems {
|
||||||
|
|
||||||
// Get the necessary data (if implemented) from the delegates else provide default values
|
itemSpacing = 0.0
|
||||||
let insets: UIEdgeInsets = delegate?.collectionView(collectionView, insetsForItemsInSection: section) ?? UIEdgeInsets.zero
|
|
||||||
let interItemSpacing: CGFloat = delegate?.collectionView(collectionView, itemSpacingInSection: section) ?? 0.0
|
|
||||||
itemSpacing = interItemSpacing
|
|
||||||
// Variables to track individual item width and cumultative height of all items as they are being laid out.
|
|
||||||
var itemSize: CGSize = .zero
|
|
||||||
|
|
||||||
layoutHeight += insets.top
|
let indexPath = IndexPath(item: item, section: section)
|
||||||
|
|
||||||
for item in 0..<collectionView.numberOfItems(inSection: section) {
|
itemSize = delegate.collectionView(collectionView, sizeForItemAtIndexPath: indexPath)
|
||||||
let indexPath = IndexPath(item: item, section: section)
|
|
||||||
|
if (layoutWidthIterator + itemSize.width + insets.left + insets.right) > collectionView.frame.width {
|
||||||
itemSize = delegate?.collectionView(collectionView, sizeForItemAtIndexPath: indexPath) ?? .zero
|
// 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
|
||||||
if (layoutWidthIterator + itemSize.width + insets.left + insets.right) > collectionView.frame.width {
|
layoutHeight += itemSize.height + rowSpacing
|
||||||
// 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 + interItemSpacing
|
let itemButtonable = delegate.collectionView(collectionView, buttonableAtIndexPath: indexPath)
|
||||||
}
|
|
||||||
|
let nextItem = item + 1
|
||||||
let frame = CGRect(x: layoutWidthIterator + insets.left, y: layoutHeight, width: itemSize.width, height: itemSize.height)
|
if nextItem < totalItems {
|
||||||
let attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath)
|
let neighbor = delegate.collectionView(collectionView, buttonableAtIndexPath: IndexPath(item: nextItem, section: section))
|
||||||
attributes.frame = frame
|
itemSpacing = getHorizontalSpacing(for: itemButtonable, neighboring: neighbor)
|
||||||
itemCache.append(attributes)
|
|
||||||
layoutWidthIterator = layoutWidthIterator + frame.width + interItemSpacing
|
|
||||||
}
|
}
|
||||||
|
|
||||||
layoutHeight += itemSize.height + insets.bottom
|
let frame = CGRect(x: layoutWidthIterator + insets.left, y: layoutHeight, width: itemSize.width, height: itemSize.height)
|
||||||
layoutWidthIterator = 0.0
|
print(frame)
|
||||||
|
let attributes = ButtonLayoutAttributes(spacing: itemSpacing, forCellWith: indexPath)
|
||||||
|
attributes.frame = frame
|
||||||
|
attributes.isButton = isButton(buttonable: itemButtonable)
|
||||||
|
itemCache.append(attributes)
|
||||||
|
|
||||||
|
layoutWidthIterator = layoutWidthIterator + frame.width + itemSpacing
|
||||||
}
|
}
|
||||||
|
print("*******")
|
||||||
|
layoutHeight += itemSize.height + insets.bottom
|
||||||
|
layoutWidthIterator = 0.0
|
||||||
|
|
||||||
|
|
||||||
//Turn into rows and re-calculate
|
//Turn into rows and re-calculate
|
||||||
var rows = [ButtonCollectionViewRow]()
|
var rows = [ButtonCollectionViewRow]()
|
||||||
var currentRowY: CGFloat = -1
|
var currentRowY: CGFloat = -1
|
||||||
|
|
||||||
for attribute in itemCache {
|
for attribute in itemCache {
|
||||||
if currentRowY != attribute.frame.midY {
|
if currentRowY != attribute.frame.midY {
|
||||||
currentRowY = attribute.frame.midY
|
currentRowY = attribute.frame.midY
|
||||||
@ -121,12 +165,156 @@ class ButtonGroupPositionLayout: UICollectionViewLayout {
|
|||||||
}
|
}
|
||||||
rows.last?.add(attribute: attribute)
|
rows.last?.add(attribute: attribute)
|
||||||
}
|
}
|
||||||
|
|
||||||
//recalculate rows based off of positions
|
//recalculate rows based off of positions
|
||||||
rows.forEach { $0.layout(for: position, with: collectionView.frame.width) }
|
rows.forEach { $0.layout(for: position, with: collectionView.frame.width) }
|
||||||
let rowAttributes = rows.flatMap { $0.attributes }
|
let rowAttributes = rows.flatMap { $0.attributes }
|
||||||
|
|
||||||
|
layoutHeight = insets.top
|
||||||
|
for item in 0..<rows.count {
|
||||||
|
let row = rows[item]
|
||||||
|
var rowSpacing = 0.0
|
||||||
|
|
||||||
|
if item > 0 && item < rows.count {
|
||||||
|
rowSpacing = row.hasButtons ? rowSpacingButton : rowSpacingTextLink
|
||||||
|
}
|
||||||
|
|
||||||
|
if item > 0 {
|
||||||
|
row.rowY = layoutHeight + rowSpacing
|
||||||
|
layoutHeight += rowSpacing
|
||||||
|
}
|
||||||
|
|
||||||
|
layoutHeight += row.rowHeight
|
||||||
|
}
|
||||||
|
layoutHeight += insets.bottom
|
||||||
|
|
||||||
|
|
||||||
itemCache = rowAttributes
|
itemCache = rowAttributes
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func isButton(buttonable: Buttonable) -> Bool{
|
||||||
|
if let _ = buttonable as? Button {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getVerticalSpacing(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 24.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 24.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 32.0
|
||||||
|
} else {
|
||||||
|
return defaultSpace
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//return defaultSpace
|
||||||
|
else {
|
||||||
|
return defaultSpace
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func layoutAttributesForElements(in rect: CGRect)-> [UICollectionViewLayoutAttributes]? {
|
override func layoutAttributesForElements(in rect: CGRect)-> [UICollectionViewLayoutAttributes]? {
|
||||||
|
|||||||
@ -103,6 +103,11 @@ open class TextLink: ButtonBase {
|
|||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Overrides
|
// MARK: - Overrides
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
override open var intrinsicContentSize: CGSize {
|
||||||
|
var itemWidth = super.intrinsicContentSize.width
|
||||||
|
return CGSize(width: itemWidth, height: height)
|
||||||
|
}
|
||||||
|
|
||||||
open override func updateView() {
|
open override func updateView() {
|
||||||
//need to set the properties so the super class
|
//need to set the properties so the super class
|
||||||
//can render out the label correctly
|
//can render out the label correctly
|
||||||
|
|||||||
@ -121,7 +121,7 @@ open class TextLinkCaret: ButtonBase {
|
|||||||
|
|
||||||
open override func updateView() {
|
open override func updateView() {
|
||||||
|
|
||||||
var updatedText = text ?? ""
|
let updatedText = text ?? ""
|
||||||
caretView.surface = surface
|
caretView.surface = surface
|
||||||
caretView.disabled = disabled
|
caretView.disabled = disabled
|
||||||
caretView.direction = iconPosition == .right ? CaretView.Direction.right : CaretView.Direction.left
|
caretView.direction = iconPosition == .right ? CaretView.Direction.right : CaretView.Direction.left
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user