Merge branch 'feature/buttonGroupUpdate' into 'develop'
removed old code See merge request BPHV_MIPS/vds_ios!21
This commit is contained in:
commit
db64bfe2fd
@ -64,6 +64,7 @@
|
|||||||
EAB5FEF5292D371F00998C17 /* ButtonBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB5FEF4292D371F00998C17 /* ButtonBase.swift */; };
|
EAB5FEF5292D371F00998C17 /* ButtonBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB5FEF4292D371F00998C17 /* ButtonBase.swift */; };
|
||||||
EAB5FEF829393A7200998C17 /* ButtonGroupConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB5FEF729393A7200998C17 /* ButtonGroupConstants.swift */; };
|
EAB5FEF829393A7200998C17 /* ButtonGroupConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB5FEF729393A7200998C17 /* ButtonGroupConstants.swift */; };
|
||||||
EAB5FF0129424ACB00998C17 /* UIControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB5FF0029424ACB00998C17 /* UIControl.swift */; };
|
EAB5FF0129424ACB00998C17 /* UIControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB5FF0029424ACB00998C17 /* UIControl.swift */; };
|
||||||
|
EAC846F3294B95CE00F685BA /* ButtonGroupCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC846F2294B95CE00F685BA /* ButtonGroupCollectionViewCell.swift */; };
|
||||||
EAC9257D29119B5400091998 /* TextLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC9257C29119B5400091998 /* TextLink.swift */; };
|
EAC9257D29119B5400091998 /* TextLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC9257C29119B5400091998 /* TextLink.swift */; };
|
||||||
EAC925832911B35400091998 /* TextLinkCaret.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC925822911B35300091998 /* TextLinkCaret.swift */; };
|
EAC925832911B35400091998 /* TextLinkCaret.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC925822911B35300091998 /* TextLinkCaret.swift */; };
|
||||||
EAC925842911C63100091998 /* Colorable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAA5EEDF28F49DB3003B3210 /* Colorable.swift */; };
|
EAC925842911C63100091998 /* Colorable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAA5EEDF28F49DB3003B3210 /* Colorable.swift */; };
|
||||||
@ -159,6 +160,7 @@
|
|||||||
EAB5FEF4292D371F00998C17 /* ButtonBase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonBase.swift; sourceTree = "<group>"; };
|
EAB5FEF4292D371F00998C17 /* ButtonBase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonBase.swift; sourceTree = "<group>"; };
|
||||||
EAB5FEF729393A7200998C17 /* ButtonGroupConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonGroupConstants.swift; sourceTree = "<group>"; };
|
EAB5FEF729393A7200998C17 /* ButtonGroupConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonGroupConstants.swift; sourceTree = "<group>"; };
|
||||||
EAB5FF0029424ACB00998C17 /* UIControl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIControl.swift; sourceTree = "<group>"; };
|
EAB5FF0029424ACB00998C17 /* UIControl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIControl.swift; sourceTree = "<group>"; };
|
||||||
|
EAC846F2294B95CE00F685BA /* ButtonGroupCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonGroupCollectionViewCell.swift; sourceTree = "<group>"; };
|
||||||
EAC9257C29119B5400091998 /* TextLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextLink.swift; sourceTree = "<group>"; };
|
EAC9257C29119B5400091998 /* TextLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextLink.swift; sourceTree = "<group>"; };
|
||||||
EAC925822911B35300091998 /* TextLinkCaret.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextLinkCaret.swift; sourceTree = "<group>"; };
|
EAC925822911B35300091998 /* TextLinkCaret.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextLinkCaret.swift; sourceTree = "<group>"; };
|
||||||
EAC925872911C9DE00091998 /* TextEntryField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextEntryField.swift; sourceTree = "<group>"; };
|
EAC925872911C9DE00091998 /* TextEntryField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextEntryField.swift; sourceTree = "<group>"; };
|
||||||
@ -229,8 +231,9 @@
|
|||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
EA0FC2C52914222900DF80B4 /* ButtonGroup.swift */,
|
EA0FC2C52914222900DF80B4 /* ButtonGroup.swift */,
|
||||||
EAB5FEEC2927E1B200998C17 /* ButtonGroupPositionLayout.swift */,
|
EAC846F2294B95CE00F685BA /* ButtonGroupCollectionViewCell.swift */,
|
||||||
EAB5FEF729393A7200998C17 /* ButtonGroupConstants.swift */,
|
EAB5FEF729393A7200998C17 /* ButtonGroupConstants.swift */,
|
||||||
|
EAB5FEEC2927E1B200998C17 /* ButtonGroupPositionLayout.swift */,
|
||||||
);
|
);
|
||||||
path = ButtonGroup;
|
path = ButtonGroup;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -668,6 +671,7 @@
|
|||||||
EA33622C2891E73B0071C351 /* FontProtocol.swift in Sources */,
|
EA33622C2891E73B0071C351 /* FontProtocol.swift in Sources */,
|
||||||
EAF7F11728A1475A00B287F5 /* RadioButton.swift in Sources */,
|
EAF7F11728A1475A00B287F5 /* RadioButton.swift in Sources */,
|
||||||
EAB1D2CD28ABE76100DAE764 /* Withable.swift in Sources */,
|
EAB1D2CD28ABE76100DAE764 /* Withable.swift in Sources */,
|
||||||
|
EAC846F3294B95CE00F685BA /* ButtonGroupCollectionViewCell.swift in Sources */,
|
||||||
EAF7F0952899861000B287F5 /* Checkbox.swift in Sources */,
|
EAF7F0952899861000B287F5 /* Checkbox.swift in Sources */,
|
||||||
EA3361C9289054C50071C351 /* Surfaceable.swift in Sources */,
|
EA3361C9289054C50071C351 /* Surfaceable.swift in Sources */,
|
||||||
EAB5FEED2927E1B200998C17 /* ButtonGroupPositionLayout.swift in Sources */,
|
EAB5FEED2927E1B200998C17 /* ButtonGroupPositionLayout.swift in Sources */,
|
||||||
|
|||||||
@ -112,209 +112,3 @@ open class SurfaceColorConfiguration: ObjectColorable {
|
|||||||
return getColor(object.surface)
|
return getColor(object.surface)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///-------------------------------------------------------------------
|
|
||||||
///MARK -- DisabledSurfaceColorable
|
|
||||||
///-------------------------------------------------------------------
|
|
||||||
public protocol DisabledSurfaceColorable: ObjectColorable {
|
|
||||||
var disabled: SurfaceColorConfiguration { get set }
|
|
||||||
var enabled: SurfaceColorConfiguration { get set }
|
|
||||||
}
|
|
||||||
|
|
||||||
extension DisabledSurfaceColorable {
|
|
||||||
public func getDisabledColor<M: Surfaceable & Disabling> (_ object: M) -> UIColor {
|
|
||||||
object.disabled ? disabled.getColor(object) : enabled.getColor(object)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Meant to be used in a Object that implements the following interfaces for 4 possible color combinations
|
|
||||||
/// - Disabling (var disabled: Bool)
|
|
||||||
/// - Surfaceable (var surface: Surface)
|
|
||||||
///
|
|
||||||
/// let model = TestModel()
|
|
||||||
/// model.surface = .dark
|
|
||||||
/// model.disabled = false
|
|
||||||
///
|
|
||||||
/// let config = DisabledSurfaceColorConfiguration()
|
|
||||||
///
|
|
||||||
/// //disabled == false
|
|
||||||
/// config.enabled.lightColor = .black
|
|
||||||
/// config.enabled.darkColor = .white
|
|
||||||
///
|
|
||||||
/// //disabled == true
|
|
||||||
/// config.disabled.lightColor = .gray
|
|
||||||
/// config.disabled.darkColor = .lightGray
|
|
||||||
///
|
|
||||||
/// let textColor = config.getColor(model) //returns .white
|
|
||||||
///
|
|
||||||
///
|
|
||||||
open class DisabledSurfaceColorConfiguration: DisabledSurfaceColorable {
|
|
||||||
public typealias ObjectType = Surfaceable & Disabling
|
|
||||||
public var disabled = SurfaceColorConfiguration()
|
|
||||||
public var enabled = SurfaceColorConfiguration()
|
|
||||||
|
|
||||||
required public init(){}
|
|
||||||
|
|
||||||
public func getColor(_ object: any ObjectType) -> UIColor {
|
|
||||||
getDisabledColor(object)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///-------------------------------------------------------------------
|
|
||||||
///MARK -- BinaryColorable
|
|
||||||
///-------------------------------------------------------------------
|
|
||||||
public protocol BinaryColorable{
|
|
||||||
var useTrueColor: Bool { get }
|
|
||||||
}
|
|
||||||
|
|
||||||
extension BinaryColorable where Self: Control {
|
|
||||||
public var useTrueColor: Bool { return isSelected }
|
|
||||||
}
|
|
||||||
|
|
||||||
///-------------------------------------------------------------------
|
|
||||||
///MARK -- BinarySurfaceColorable
|
|
||||||
///-------------------------------------------------------------------
|
|
||||||
public protocol BinarySurfaceColorable: ObjectColorable {
|
|
||||||
var forTrue: SurfaceColorConfiguration { get set }
|
|
||||||
var forFalse: SurfaceColorConfiguration { get set }
|
|
||||||
}
|
|
||||||
|
|
||||||
extension BinarySurfaceColorable {
|
|
||||||
public func getBinaryColor<M: Surfaceable & BinaryColorable>(_ object: M) -> UIColor {
|
|
||||||
object.useTrueColor ? forTrue.getColor(object) : forFalse.getColor(object)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Meant to be used in a Object that implements the following interfaces for 4 possible color combinations
|
|
||||||
/// - BinaryColorable (var userTrueColor: Bool)
|
|
||||||
/// - Surfaceable (var surface: Surface)
|
|
||||||
///
|
|
||||||
/// let model = TestModel()
|
|
||||||
/// model.surface = .dark
|
|
||||||
/// model.on = true //this is read in the extension var userTrueColor
|
|
||||||
/// let config = BinarySurfaceColorConfiguration()
|
|
||||||
///
|
|
||||||
/// //True from BinaryColorable.userTrueColor
|
|
||||||
/// config.forTrue.lightColor = .black
|
|
||||||
/// config.forTrue.darkColor = .white
|
|
||||||
///
|
|
||||||
/// //False from BinaryColorable.userTrueColor
|
|
||||||
/// config.forFalse.lightColor = .red
|
|
||||||
/// config.forFalse.darkColor = .red
|
|
||||||
///
|
|
||||||
/// let textColor = config.getColor(model) //returns .white
|
|
||||||
///
|
|
||||||
///
|
|
||||||
final public class BinarySurfaceColorConfiguration: BinarySurfaceColorable {
|
|
||||||
public typealias ObjectType = Surfaceable & BinaryColorable
|
|
||||||
public var forTrue = SurfaceColorConfiguration()
|
|
||||||
public var forFalse = SurfaceColorConfiguration()
|
|
||||||
|
|
||||||
required public init(){}
|
|
||||||
|
|
||||||
public func getColor(_ object: any ObjectType) -> UIColor {
|
|
||||||
getBinaryColor(object)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///-------------------------------------------------------------------
|
|
||||||
///MARK -- BinaryDisabledSurfaceColorable
|
|
||||||
///-------------------------------------------------------------------
|
|
||||||
|
|
||||||
public protocol BinaryDisabledSurfaceColorable: ObjectColorable {
|
|
||||||
var forTrue: DisabledSurfaceColorConfiguration { get set }
|
|
||||||
var forFalse: DisabledSurfaceColorConfiguration { get set }
|
|
||||||
}
|
|
||||||
|
|
||||||
extension BinaryDisabledSurfaceColorable {
|
|
||||||
public func getBinaryColor<M: Disabling & Surfaceable & BinaryColorable>(_ object: M) -> UIColor {
|
|
||||||
object.useTrueColor ? forTrue.getColor(object) : forFalse.getColor(object)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Meant to be used in a Object that implements the following interfaces for 8 possible color combinations
|
|
||||||
/// - BinaryColorable (var userTrueColor: Bool)
|
|
||||||
/// - Disabling (var disabled: Bool)
|
|
||||||
/// - Surfaceable (var surface: Surface)
|
|
||||||
///
|
|
||||||
/// let model = TestModel()
|
|
||||||
/// model.on = false
|
|
||||||
/// model.disabled = false
|
|
||||||
/// model.surface = .light
|
|
||||||
/// let config = BinaryDisabledSurfaceColorConfiguration()
|
|
||||||
///
|
|
||||||
/// //True
|
|
||||||
/// config.forTrue.enabled.lightColor = .black
|
|
||||||
/// config.forTrue.enabled.darkColor = .white
|
|
||||||
/// config.forTrue.disabled.lightColor = .darkGray
|
|
||||||
/// config.forTrue.disabled.darkColor = .lightGray
|
|
||||||
///
|
|
||||||
/// //False
|
|
||||||
/// config.forFalse.enabled.lightColor = .red
|
|
||||||
/// config.forFalse.enabled.darkColor = .red
|
|
||||||
/// config.forFalse.disabled.lightColor =.darkGray
|
|
||||||
/// config.forFalse.disabled.darkColor = .lightGray
|
|
||||||
///
|
|
||||||
/// let textColor = config.getColor(model)
|
|
||||||
///
|
|
||||||
///
|
|
||||||
final public class BinaryDisabledSurfaceColorConfiguration: BinaryDisabledSurfaceColorable {
|
|
||||||
public typealias ObjectType = Disabling & Surfaceable & BinaryColorable
|
|
||||||
public var forTrue = DisabledSurfaceColorConfiguration()
|
|
||||||
public var forFalse = DisabledSurfaceColorConfiguration()
|
|
||||||
|
|
||||||
required public init(){}
|
|
||||||
|
|
||||||
public func getColor(_ object: any ObjectType) -> UIColor {
|
|
||||||
getBinaryColor(object)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class ControlStateColorConfiguration: ObjectColorable {
|
|
||||||
public typealias ObjectType = UIControl & Surfaceable
|
|
||||||
public var disabled = SurfaceColorConfiguration()
|
|
||||||
public var normal = SurfaceColorConfiguration()
|
|
||||||
public var highlighted: SurfaceColorConfiguration?
|
|
||||||
public var selected: SurfaceColorConfiguration?
|
|
||||||
public var error: SurfaceColorConfiguration?
|
|
||||||
|
|
||||||
required public init(){}
|
|
||||||
|
|
||||||
public func setColorable(_ config: SurfaceColorConfiguration, for state: UIControl.State) {
|
|
||||||
switch state {
|
|
||||||
case .disabled:
|
|
||||||
disabled = config
|
|
||||||
|
|
||||||
case .highlighted:
|
|
||||||
highlighted = config
|
|
||||||
|
|
||||||
case .selected:
|
|
||||||
selected = config
|
|
||||||
|
|
||||||
case .error:
|
|
||||||
error = config
|
|
||||||
|
|
||||||
default:
|
|
||||||
normal = config
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public func getColor(_ object: any ObjectType) -> UIColor {
|
|
||||||
|
|
||||||
if object.state == .disabled {
|
|
||||||
return disabled.getColor(object)
|
|
||||||
|
|
||||||
} else if let highlighted, object.state == .highlighted {
|
|
||||||
return highlighted.getColor(object)
|
|
||||||
|
|
||||||
} else if let selected, object.state == .selected {
|
|
||||||
return selected.getColor(object)
|
|
||||||
|
|
||||||
} else if let error, object.state == .error {
|
|
||||||
return error.getColor(object)
|
|
||||||
|
|
||||||
} else {
|
|
||||||
return normal.getColor(object)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -170,25 +170,9 @@ open class Button: ButtonBase, Useable {
|
|||||||
minWidthConstraint?.isActive = true
|
minWidthConstraint?.isActive = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------
|
|
||||||
// MARK: - PRIVATE
|
|
||||||
//--------------------------------------------------
|
|
||||||
|
|
||||||
private class UseableColorConfiguration: ObjectColorable {
|
|
||||||
typealias ObjectType = Buttonable & Useable
|
|
||||||
public var primary = ControlStateColorConfiguration()
|
|
||||||
public var secondary = ControlStateColorConfiguration()
|
|
||||||
|
|
||||||
required public init(){}
|
|
||||||
|
|
||||||
public func getColor(_ object: ObjectType) -> UIColor {
|
|
||||||
return object.use == .primary ? primary.getColor(object) : secondary.getColor(object)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fileprivate extension ButtonSize {
|
internal extension ButtonSize {
|
||||||
|
|
||||||
var height: CGFloat {
|
var height: CGFloat {
|
||||||
switch self {
|
switch self {
|
||||||
|
|||||||
@ -19,6 +19,10 @@ public protocol Buttonable: UIControl, Surfaceable, Disabling {
|
|||||||
|
|
||||||
@objc(VDSButtonBase)
|
@objc(VDSButtonBase)
|
||||||
open class ButtonBase: UIButton, Buttonable, Handlerable, ViewProtocol, Resettable {
|
open class ButtonBase: UIButton, Buttonable, Handlerable, ViewProtocol, Resettable {
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Configuration Properties
|
||||||
|
//--------------------------------------------------
|
||||||
|
private let hitAreaHeight = 44.0
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Combine Properties
|
// MARK: - Combine Properties
|
||||||
@ -194,4 +198,28 @@ open class ButtonBase: UIButton, Buttonable, Handlerable, ViewProtocol, Resettab
|
|||||||
setAttributedTitle(mutableText, for: .normal)
|
setAttributedTitle(mutableText, for: .normal)
|
||||||
setAttributedTitle(mutableText, for: .highlighted)
|
setAttributedTitle(mutableText, for: .highlighted)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
open override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||||
|
let size = intrinsicContentSize
|
||||||
|
// Create a minimumHitArea variable with a value that represents the minimum size of the hit area you want to create for the button.
|
||||||
|
let minimumHitArea = CGSize(width: size.width, height: hitAreaHeight)
|
||||||
|
|
||||||
|
// Create a new hitFrame variable that is the same size as the minimumHitArea variable, but is centered on the button's frame.
|
||||||
|
let hitFrame = CGRect(
|
||||||
|
x: self.bounds.midX - minimumHitArea.width / 2,
|
||||||
|
y: self.bounds.midY - minimumHitArea.height / 2,
|
||||||
|
width: minimumHitArea.width,
|
||||||
|
height: minimumHitArea.height
|
||||||
|
)
|
||||||
|
|
||||||
|
// If the point that was passed to the hitTest(_:with:) method is within the hitFrame, return the button itself. This will cause the button to handle the touch event.
|
||||||
|
if hitFrame.contains(point) {
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the point is not within the hitFrame, return nil. This will cause the touch event to be handled by another view.
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -32,6 +32,9 @@ open class ButtonGroup: View, UICollectionViewDataSource, UICollectionViewDelega
|
|||||||
//If provided, width of Button components will be rendered based on this value. If omitted, default button widths are rendered.
|
//If provided, width of Button components will be rendered based on this value. If omitted, default button widths are rendered.
|
||||||
open var buttonWidth: CGFloat? {
|
open var buttonWidth: CGFloat? {
|
||||||
didSet {
|
didSet {
|
||||||
|
if let buttonWidth, let buttonPercentage, buttonWidth > 0, buttonPercentage > 0{
|
||||||
|
self.buttonPercentage = nil
|
||||||
|
}
|
||||||
buttons.forEach { button in
|
buttons.forEach { button in
|
||||||
if let button = button as? Button {
|
if let button = button as? Button {
|
||||||
button.width = buttonWidth
|
button.width = buttonWidth
|
||||||
@ -41,6 +44,23 @@ open class ButtonGroup: View, UICollectionViewDataSource, UICollectionViewDelega
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var _buttonPercentage: CGFloat?
|
||||||
|
open var buttonPercentage: CGFloat? {
|
||||||
|
get { _buttonPercentage }
|
||||||
|
set {
|
||||||
|
if let newValue, newValue <= 100.0, rowQuantity > 0 {
|
||||||
|
_buttonPercentage = newValue
|
||||||
|
} else {
|
||||||
|
_buttonPercentage = nil
|
||||||
|
}
|
||||||
|
if let buttonWidth, let buttonPercentage, buttonWidth > 0, buttonPercentage > 0 {
|
||||||
|
self.buttonWidth = nil
|
||||||
|
}
|
||||||
|
positionLayout.buttonPercentage = buttonPercentage
|
||||||
|
didChange()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Private Properties
|
// MARK: - Private Properties
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
@ -64,7 +84,7 @@ open class ButtonGroup: View, UICollectionViewDataSource, UICollectionViewDelega
|
|||||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||||
$0.dataSource = self
|
$0.dataSource = self
|
||||||
$0.delegate = self
|
$0.delegate = self
|
||||||
$0.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "collectionViewCell")
|
$0.register(ButtonGroupCollectionViewCell.self, forCellWithReuseIdentifier: "collectionViewCell")
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@ -146,9 +166,10 @@ open class ButtonGroup: View, UICollectionViewDataSource, UICollectionViewDelega
|
|||||||
|
|
||||||
public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
||||||
let button = buttons[indexPath.row]
|
let button = buttons[indexPath.row]
|
||||||
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionViewCell", for: indexPath)
|
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionViewCell", for: indexPath) as? ButtonGroupCollectionViewCell else { return UICollectionViewCell() }
|
||||||
cell.subviews.forEach { $0.removeFromSuperview() }
|
cell.subviews.forEach { $0.removeFromSuperview() }
|
||||||
cell.addSubview(button)
|
cell.addSubview(button)
|
||||||
|
cell.buttonable = button
|
||||||
button.pinLeading()
|
button.pinLeading()
|
||||||
button.pinTrailing()
|
button.pinTrailing()
|
||||||
button.centerYAnchor.constraint(equalTo: cell.centerYAnchor).isActive = true
|
button.centerYAnchor.constraint(equalTo: cell.centerYAnchor).isActive = true
|
||||||
|
|||||||
@ -0,0 +1,40 @@
|
|||||||
|
//
|
||||||
|
// ButtonGroupCollectionViewCell.swift
|
||||||
|
// VDS
|
||||||
|
//
|
||||||
|
// Created by Matt Bruce on 12/15/22.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
|
||||||
|
/// Cell is needed since the buttonable hitArea "can" be outside of it's container rectangle
|
||||||
|
public class ButtonGroupCollectionViewCell: UICollectionViewCell {
|
||||||
|
|
||||||
|
var buttonable: Buttonable?
|
||||||
|
|
||||||
|
open override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||||
|
guard let buttonable else { return nil }
|
||||||
|
|
||||||
|
// Create a minimumHitArea variable with a value that represents the minimum size of the hit area you want to create for the button.
|
||||||
|
let minimumHitArea = CGSize(width: buttonable.intrinsicContentSize.width, height: 44)
|
||||||
|
|
||||||
|
// Create a new hitFrame variable that is the same size as the minimumHitArea variable, but is centered on the button's frame.
|
||||||
|
let hitFrame = CGRect(
|
||||||
|
x: self.bounds.midX - minimumHitArea.width / 2,
|
||||||
|
y: self.bounds.midY - minimumHitArea.height / 2,
|
||||||
|
width: minimumHitArea.width,
|
||||||
|
height: minimumHitArea.height
|
||||||
|
)
|
||||||
|
|
||||||
|
// If the point that was passed to the hitTest(_:with:) method is within the hitFrame, return the button itself. This will cause the button to handle the touch event.
|
||||||
|
if hitFrame.contains(point) {
|
||||||
|
return buttonable
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the point is not within the hitFrame, return nil. This will cause the touch event to be handled by another view.
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -8,19 +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 {
|
||||||
|
case horizontal, vertical
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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 {
|
||||||
|
|
||||||
static func getHorizontalSpacing(for primary: Buttonable, neighboring: Buttonable) -> CGFloat {
|
|
||||||
let defaultSpace = 12.0
|
|
||||||
//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
|
||||||
}
|
}
|
||||||
@ -28,29 +37,33 @@ 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 16.0
|
return axis == .horizontal ? 16.0 : 24.0
|
||||||
} else {
|
} else {
|
||||||
return defaultSpace
|
return defaultSpace
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//text link caret
|
//text link caret
|
||||||
else if let _ = primary as? TextLinkCaret {
|
else if let _ = primary as? TextLinkCaret {
|
||||||
if let _ = neighboring as? TextLinkCaret {
|
if let neighboringButton = neighboring as? Button, neighboringButton.size == .large {
|
||||||
return 24.0
|
return axis == .horizontal ? 24.0 : 24.0
|
||||||
} else {
|
} else if let _ = neighboring as? TextLinkCaret {
|
||||||
return defaultSpace
|
return axis == .horizontal ? 24.0 : 24.0
|
||||||
}
|
} else if let neighboringTextLink = neighboring as? TextLink, neighboringTextLink.size == .large {
|
||||||
|
return axis == .horizontal ? 24.0 : 24.0
|
||||||
|
} else {
|
||||||
|
return defaultSpace
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//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 16.0
|
return axis == .horizontal ? 16.0 : 24.0
|
||||||
} else {
|
} else {
|
||||||
return defaultSpace
|
return defaultSpace
|
||||||
}
|
}
|
||||||
@ -58,7 +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 16.0
|
return axis == .horizontal ? 16.0 : 24.0
|
||||||
|
} else if let _ = neighboring as? Button {
|
||||||
|
return axis == .horizontal ? 16.0 : 32.0
|
||||||
} else {
|
} else {
|
||||||
return defaultSpace
|
return defaultSpace
|
||||||
}
|
}
|
||||||
@ -69,68 +84,54 @@ struct ButtonGroupConstants {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static func getVerticalSpacing(for primary: Buttonable, neighboring: Buttonable) -> CGFloat {
|
|
||||||
let defaultSpace = 12.0
|
//
|
||||||
//large button
|
|
||||||
if let button = primary as? Button, button.size == .large {
|
/// Gets the tallest buttonables within the row
|
||||||
if let neighboringButton = neighboring as? Button, neighboringButton.size == .large {
|
/// - Parameter row: Row that includes the attributes
|
||||||
return 12.0
|
/// - Returns: Array of [ButtonLayoutAttributes] of the tallest items
|
||||||
} else if let neighboringTextLink = neighboring as? TextLink, neighboringTextLink.size == .large {
|
private static func getTallestAttributes(for row: ButtonCollectionViewRow) -> [ButtonLayoutAttributes] {
|
||||||
return 16.0
|
var height = 0.0
|
||||||
} else if let _ = neighboring as? TextLinkCaret {
|
var foundIndexes:[Int] = []
|
||||||
return 24.0
|
for (index, attribute) in row.attributes.enumerated() {
|
||||||
} else {
|
if attribute.frame.height >= height {
|
||||||
return defaultSpace
|
height = attribute.frame.height
|
||||||
|
foundIndexes.append(index)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//large text link
|
return foundIndexes.compactMap { row.attributes[$0] }
|
||||||
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 {
|
/// Gets the vertical spacing that will go between rows.
|
||||||
return 24.0
|
/// - Parameters:
|
||||||
} else if let neighboringTextLink = neighboring as? TextLink, neighboringTextLink.size == .large {
|
/// - row: Primary row that the space will go between
|
||||||
return 24.0
|
/// - neighboringRow: Secondary row that will be below the Primary
|
||||||
} else {
|
/// - Returns: Amount of space that should live between these rows based off of the items. The largest space will win when the comparison occurs.
|
||||||
return defaultSpace
|
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
|
||||||
}
|
}
|
||||||
//text link caret
|
|
||||||
else if let _ = primary as? TextLinkCaret {
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//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 if let neighboringButton = neighboring as? Button, neighboringButton.size == .small {
|
|
||||||
return 24.0
|
|
||||||
} else {
|
|
||||||
return defaultSpace
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//return defaultSpace
|
|
||||||
else {
|
else {
|
||||||
return defaultSpace
|
return defaultSpace
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,6 +22,8 @@ class ButtonCollectionViewRow {
|
|||||||
attributes.contains(where: { $0.isButton })
|
attributes.contains(where: { $0.isButton })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var buttonPercentage: CGFloat?
|
||||||
|
|
||||||
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 + attribute.spacing
|
return result + attribute.frame.width + attribute.spacing
|
||||||
@ -50,6 +52,54 @@ class ButtonCollectionViewRow {
|
|||||||
let height = rowHeight
|
let height = rowHeight
|
||||||
attributes.last?.spacing = 0
|
attributes.last?.spacing = 0
|
||||||
|
|
||||||
|
//check to see if you have buttons and there is a percentage
|
||||||
|
if let buttonPercentage, hasButtons, buttonPercentage > 0 {
|
||||||
|
|
||||||
|
var usedSpace = 0.0
|
||||||
|
//get the width for the buttons
|
||||||
|
for attribute in attributes {
|
||||||
|
if !attribute.isButton {
|
||||||
|
usedSpace += attribute.frame.width
|
||||||
|
}
|
||||||
|
usedSpace += attribute.spacing
|
||||||
|
}
|
||||||
|
let buttonAvailableSpace = collectionViewWidth - usedSpace
|
||||||
|
let realPercentage = (buttonPercentage / 100)
|
||||||
|
let buttonWidth = realPercentage * buttonAvailableSpace
|
||||||
|
// print("buttonPercentage :\(realPercentage)")
|
||||||
|
// print("collectionView width:\(collectionViewWidth)")
|
||||||
|
// print("usedSpace width:\(usedSpace)")
|
||||||
|
// print("button available width:\(buttonAvailableSpace)")
|
||||||
|
// print("each button width:\(buttonWidth)\n")
|
||||||
|
// print("minimum widht:\(ButtonSize.large.minimumWidth)")
|
||||||
|
// test sizing
|
||||||
|
var testSize = 0.0
|
||||||
|
var buttonCount = 0.0
|
||||||
|
for attribute in attributes {
|
||||||
|
if attribute.isButton {
|
||||||
|
testSize += buttonWidth
|
||||||
|
buttonCount += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if buttonWidth >= ButtonSize.large.minimumWidth {
|
||||||
|
if testSize <= buttonAvailableSpace {
|
||||||
|
for attribute in attributes {
|
||||||
|
if attribute.isButton {
|
||||||
|
attribute.frame.size.width = buttonWidth
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let distributedSize = buttonAvailableSpace / buttonCount
|
||||||
|
for attribute in attributes {
|
||||||
|
if attribute.isButton {
|
||||||
|
attribute.frame.size.width = distributedSize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch position {
|
switch position {
|
||||||
case .left:
|
case .left:
|
||||||
break
|
break
|
||||||
@ -62,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
|
||||||
}
|
}
|
||||||
@ -80,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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,6 +156,7 @@ class ButtonGroupPositionLayout: UICollectionViewLayout {
|
|||||||
var layoutHeight: CGFloat = 0.0
|
var layoutHeight: CGFloat = 0.0
|
||||||
var position: ButtonPosition = .left
|
var position: ButtonPosition = .left
|
||||||
var rowQuantity: Int = 0
|
var rowQuantity: Int = 0
|
||||||
|
var buttonPercentage: CGFloat?
|
||||||
|
|
||||||
private var itemCache: [ButtonLayoutAttributes] = []
|
private var itemCache: [ButtonLayoutAttributes] = []
|
||||||
|
|
||||||
@ -167,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)
|
||||||
@ -196,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
|
||||||
}
|
}
|
||||||
@ -205,21 +266,16 @@ class ButtonGroupPositionLayout: UICollectionViewLayout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// recalculate rows x based off of positions
|
// recalculate rows x based off of positions
|
||||||
rows.forEach { $0.layout(for: position, with: collectionViewWidth) }
|
rows.forEach {
|
||||||
|
$0.buttonPercentage = buttonPercentage
|
||||||
|
$0.layout(for: position, with: collectionViewWidth)
|
||||||
|
}
|
||||||
|
|
||||||
let rowAttributes = rows.flatMap { $0.attributes }
|
let rowAttributes = rows.flatMap { $0.attributes }
|
||||||
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] = []
|
||||||
|
|
||||||
|
|||||||
@ -17,7 +17,6 @@ open class TextLink: ButtonBase {
|
|||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Private Properties
|
// MARK: - Private Properties
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
private var heightConstraint: NSLayoutConstraint?
|
|
||||||
private var lineHeightConstraint: NSLayoutConstraint?
|
private var lineHeightConstraint: NSLayoutConstraint?
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
@ -83,9 +82,6 @@ open class TextLink: ButtonBase {
|
|||||||
lineHeightConstraint = line.heightAnchor.constraint(equalToConstant: 1.0)
|
lineHeightConstraint = line.heightAnchor.constraint(equalToConstant: 1.0)
|
||||||
lineHeightConstraint?.isActive = true
|
lineHeightConstraint?.isActive = true
|
||||||
}
|
}
|
||||||
|
|
||||||
heightConstraint = heightAnchor.constraint(equalToConstant: height)
|
|
||||||
heightConstraint?.isActive = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
open override func reset() {
|
open override func reset() {
|
||||||
@ -99,18 +95,15 @@ open class TextLink: ButtonBase {
|
|||||||
// MARK: - Overrides
|
// MARK: - Overrides
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
open override var intrinsicContentSize: CGSize {
|
open override var intrinsicContentSize: CGSize {
|
||||||
let size = titleLabel?.intrinsicContentSize ?? super.intrinsicContentSize
|
return titleLabel?.intrinsicContentSize ?? super.intrinsicContentSize
|
||||||
return CGSize(width: size.width, 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
|
||||||
heightConstraint?.constant = height
|
|
||||||
line.backgroundColor = textColor
|
line.backgroundColor = textColor
|
||||||
|
|
||||||
//always call last so the label is rendered
|
//always call last so the label is rendered
|
||||||
super.updateView()
|
super.updateView()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,8 +21,6 @@ open class TextLinkCaret: ButtonBase {
|
|||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Private Properties
|
// MARK: - Private Properties
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
private var heightConstraint: NSLayoutConstraint?
|
|
||||||
|
|
||||||
open override var typograpicalStyle: TypographicalStyle {
|
open override var typograpicalStyle: TypographicalStyle {
|
||||||
TypographicalStyle.BoldBodyLarge
|
TypographicalStyle.BoldBodyLarge
|
||||||
}
|
}
|
||||||
@ -91,8 +89,6 @@ open class TextLinkCaret: ButtonBase {
|
|||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
open override func setup() {
|
open override func setup() {
|
||||||
super.setup()
|
super.setup()
|
||||||
//constraints
|
|
||||||
heightAnchor.constraint(greaterThanOrEqualToConstant: height).isActive = true
|
|
||||||
|
|
||||||
let size = caretView.size!.dimensions()
|
let size = caretView.size!.dimensions()
|
||||||
caretView.frame = .init(x: 0, y: 0, width: size.width, height: size.height)
|
caretView.frame = .init(x: 0, y: 0, width: size.width, height: size.height)
|
||||||
@ -115,7 +111,7 @@ open class TextLinkCaret: ButtonBase {
|
|||||||
if let caretWidth = caretView.size?.dimensions().width {
|
if let caretWidth = caretView.size?.dimensions().width {
|
||||||
itemWidth += caretWidth
|
itemWidth += caretWidth
|
||||||
}
|
}
|
||||||
return CGSize(width: itemWidth, height: height)
|
return CGSize(width: itemWidth, height: size.height)
|
||||||
}
|
}
|
||||||
|
|
||||||
open override func updateView() {
|
open override func updateView() {
|
||||||
@ -129,8 +125,8 @@ open class TextLinkCaret: ButtonBase {
|
|||||||
let location = iconPosition == .right ? updatedText.count : 0
|
let location = iconPosition == .right ? updatedText.count : 0
|
||||||
|
|
||||||
imageAttribute = ImageLabelAttribute(location: location,
|
imageAttribute = ImageLabelAttribute(location: location,
|
||||||
image: image,
|
image: image,
|
||||||
tintColor: textColor)
|
tintColor: textColor)
|
||||||
|
|
||||||
super.updateView()
|
super.updateView()
|
||||||
}
|
}
|
||||||
@ -159,11 +155,9 @@ internal class CaretView: View {
|
|||||||
|
|
||||||
public var size: CaretSize? { didSet{ didChange() } }
|
public var size: CaretSize? { didSet{ didChange() } }
|
||||||
|
|
||||||
public var colorConfiguration: AnyColorable = DisabledSurfaceColorConfiguration().with {
|
public var colorConfiguration: AnyColorable = ViewColorConfiguration().with {
|
||||||
$0.disabled.lightColor = VDSColor.elementsSecondaryOnlight
|
$0.setSurfaceColors(VDSColor.elementsSecondaryOnlight, VDSColor.elementsSecondaryOndark, forDisabled: true)
|
||||||
$0.disabled.darkColor = VDSColor.elementsSecondaryOndark
|
$0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forDisabled: false)
|
||||||
$0.enabled.lightColor = VDSColor.elementsPrimaryOnlight
|
|
||||||
$0.enabled.darkColor = VDSColor.elementsPrimaryOndark
|
|
||||||
}.eraseToAnyColorable()
|
}.eraseToAnyColorable()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -27,7 +27,7 @@ public class SoloCheckbox: CheckboxBase{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@objc(VDSCheckboxBase)
|
@objc(VDSCheckboxBase)
|
||||||
open class CheckboxBase: Control, Accessable, DataTrackable, BinaryColorable, Errorable {
|
open class CheckboxBase: Control, Accessable, DataTrackable, Errorable {
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Initializers
|
// MARK: - Initializers
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|||||||
@ -27,7 +27,7 @@ public class SoloRadioBox: RadioBoxBase{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@objc(VDSRadioBoxBase)
|
@objc(VDSRadioBoxBase)
|
||||||
open class RadioBoxBase: Control, BinaryColorable, Accessable, DataTrackable{
|
open class RadioBoxBase: Control, Accessable, DataTrackable{
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Initializers
|
// MARK: - Initializers
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|||||||
@ -34,7 +34,7 @@ public class SoloRadioButton: RadioButtonBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@objc(VDSRadioButtonBase)
|
@objc(VDSRadioButtonBase)
|
||||||
open class RadioButtonBase: Control, Accessable, DataTrackable, BinaryColorable, Errorable {
|
open class RadioButtonBase: Control, Accessable, DataTrackable, Errorable {
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Initializers
|
// MARK: - Initializers
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|||||||
@ -31,7 +31,7 @@ public class SolorRadioSwatch: RadioSwatchBase{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@objc(VDSRadioSwatchBase)
|
@objc(VDSRadioSwatchBase)
|
||||||
open class RadioSwatchBase: Control, Accessable, DataTrackable, BinaryColorable {
|
open class RadioSwatchBase: Control, Accessable, DataTrackable {
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Initializers
|
// MARK: - Initializers
|
||||||
|
|||||||
@ -358,26 +358,3 @@ open class EntryField: Control, Accessable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------
|
|
||||||
// MARK: - Color Class Configurations
|
|
||||||
//--------------------------------------------------
|
|
||||||
internal class ErrorDisabledSurfaceColorConfiguration: DisabledSurfaceColorable {
|
|
||||||
typealias ModelType = Errorable & Surfaceable & Disabling
|
|
||||||
var error = SurfaceColorConfiguration()
|
|
||||||
var disabled = SurfaceColorConfiguration()
|
|
||||||
var enabled = SurfaceColorConfiguration()
|
|
||||||
|
|
||||||
required public init(){}
|
|
||||||
|
|
||||||
func getColor(_ viewModel: any ModelType) -> UIColor {
|
|
||||||
//only show error is enabled and showError == true
|
|
||||||
let showErrorColor = !viewModel.disabled && viewModel.showError
|
|
||||||
|
|
||||||
if showErrorColor {
|
|
||||||
return error.getColor(viewModel)
|
|
||||||
} else {
|
|
||||||
return getDisabledColor(viewModel)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -185,32 +185,6 @@ open class TextEntryFieldBase: EntryField {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class TextEntryFieldColorConfiguration: DisabledSurfaceColorable {
|
|
||||||
var success = SurfaceColorConfiguration()
|
|
||||||
var error = SurfaceColorConfiguration()
|
|
||||||
var disabled = SurfaceColorConfiguration()
|
|
||||||
var enabled = SurfaceColorConfiguration()
|
|
||||||
|
|
||||||
required init(){}
|
|
||||||
|
|
||||||
func getColor(_ object: TextEntryField) -> UIColor {
|
|
||||||
//only show error is enabled and showError == true
|
|
||||||
let showErrorColor = !object.disabled && object.showError
|
|
||||||
let showSuccessColor = !object.disabled && object.showSuccess
|
|
||||||
|
|
||||||
if showErrorColor {
|
|
||||||
return error.getColor(object)
|
|
||||||
|
|
||||||
} else if showSuccessColor {
|
|
||||||
return success.getColor(object)
|
|
||||||
|
|
||||||
} else {
|
|
||||||
return getDisabledColor(object)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension TextEntryFieldType {
|
extension TextEntryFieldType {
|
||||||
|
|||||||
@ -42,7 +42,7 @@ public class Toggle: ToggleBase{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@objc(VDSToggleBase)
|
@objc(VDSToggleBase)
|
||||||
open class ToggleBase: Control, Accessable, DataTrackable, BinaryColorable {
|
open class ToggleBase: Control, Accessable, DataTrackable {
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Initializers
|
// MARK: - Initializers
|
||||||
|
|||||||
@ -119,9 +119,9 @@ extension UIView {
|
|||||||
|
|
||||||
|
|
||||||
extension UIView {
|
extension UIView {
|
||||||
public func debugBorder(show shouldShow: Bool = true) {
|
public func debugBorder(show shouldShow: Bool = true, color: UIColor = .red) {
|
||||||
if shouldShow {
|
if shouldShow {
|
||||||
layer.borderColor = UIColor.red.cgColor
|
layer.borderColor = color.cgColor
|
||||||
layer.borderWidth = 1
|
layer.borderWidth = 1
|
||||||
} else {
|
} else {
|
||||||
layer.borderColor = UIColor.clear.cgColor
|
layer.borderColor = UIColor.clear.cgColor
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user