Missed a few "fill" types and refactored to use a multiplier

Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
This commit is contained in:
Matt Bruce 2024-07-18 15:34:03 -05:00
parent bf40368dc4
commit b91017068c

View File

@ -74,7 +74,7 @@ open class TileContainerBase<PaddingType: DefaultValuing>: Control where Padding
case custom(UIColor)
private var reflectedValue: String { String(reflecting: self) }
public static func == (lhs: Self, rhs: Self) -> Bool {
lhs.reflectedValue == rhs.reflectedValue
}
@ -86,7 +86,7 @@ open class TileContainerBase<PaddingType: DefaultValuing>: Control where Padding
case gradient(UIColor, UIColor)
case none
}
/// Enum used to describe the aspect ratios used for this component.
public enum AspectRatio: String, CaseIterable {
case ratio1x1 = "1:1"
@ -109,7 +109,7 @@ open class TileContainerBase<PaddingType: DefaultValuing>: Control where Padding
$0.contentMode = .scaleAspectFill
$0.clipsToBounds = true
}
open var containerView = View().with {
$0.setContentHuggingPriority(.defaultLow, for: .horizontal)
$0.setContentHuggingPriority(.defaultLow, for: .vertical)
@ -125,27 +125,27 @@ open class TileContainerBase<PaddingType: DefaultValuing>: Control where Padding
/// This is the container in which views will be pinned.
open var contentView = View()
/// This is the view used to show the high light color for a onClick.
open var highlightView = View().with {
$0.isUserInteractionEnabled = false
}
/// This controls the aspect ratio for the component.
open var aspectRatio: AspectRatio = .ratio1x1 { didSet { setNeedsUpdate() } }
/// Sets the background color for the component.
open var color: BackgroundColor? { didSet { setNeedsUpdate() } }
/// Sets the background effect for the component.
open var backgroundEffect: BackgroundEffect = .none { didSet { setNeedsUpdate() } }
/// Sets the inside padding for the component
open var padding: PaddingType = PaddingType.defaultValue { didSet { setNeedsUpdate() } }
/// Applies a background color if backgroundImage prop fails or has trouble loading.
open var imageFallbackColor: Surface = .light { didSet { setNeedsUpdate() } }
private var _width: CGFloat?
/// Sets the width for the component. Accepts a pixel value.
open var width: CGFloat? {
@ -159,7 +159,7 @@ open class TileContainerBase<PaddingType: DefaultValuing>: Control where Padding
setNeedsUpdate()
}
}
private var _height: CGFloat?
/// Sets the height for the component. Accepts a pixel value.
open var height: CGFloat? {
@ -179,13 +179,14 @@ open class TileContainerBase<PaddingType: DefaultValuing>: Control where Padding
/// Determines if there is a drop shadow or not.
open var showDropShadow: Bool = false { didSet { setNeedsUpdate() } }
//--------------------------------------------------
// MARK: - Constraints
//--------------------------------------------------
internal var widthConstraint: NSLayoutConstraint?
internal var heightConstraint: NSLayoutConstraint?
internal var aspectRatioConstraint: NSLayoutConstraint?
//--------------------------------------------------
// MARK: - Configuration
//--------------------------------------------------
@ -228,13 +229,13 @@ open class TileContainerBase<PaddingType: DefaultValuing>: Control where Padding
containerView.addSubview(backgroundImageView)
backgroundImageView.pinToSuperView()
containerView.addSubview(contentView)
contentView.pinToSuperView()
containerView.addSubview(highlightView)
highlightView.pinToSuperView()
widthConstraint = widthAnchor.constraint(equalToConstant: 0).deactivate()
heightConstraint = heightAnchor.constraint(equalToConstant: 0).deactivate()
@ -266,7 +267,7 @@ open class TileContainerBase<PaddingType: DefaultValuing>: Control where Padding
setNeedsUpdate()
}
}.store(in: &subscribers)
}
/// Overriden to take the hit if there is an onClickSubscriber and the view is not a UIControl
@ -291,7 +292,7 @@ open class TileContainerBase<PaddingType: DefaultValuing>: Control where Padding
shouldUpdateView = true
setNeedsUpdate()
}
/// Used to make changes to the View based off a change events or from local properties.
open override func updateView() {
super.updateView()
@ -301,13 +302,14 @@ open class TileContainerBase<PaddingType: DefaultValuing>: Control where Padding
containerView.layer.borderColor = borderColorConfiguration.getColor(self).cgColor
containerView.layer.borderWidth = showBorder ? VDSFormControls.borderWidth : 0
contentView.removeConstraints()
contentView.pinToSuperView(.uniform(padding.value))
updateContainerView()
}
open override var accessibilityElements: [Any]? {
get {
var items = [Any]()
@ -328,7 +330,7 @@ open class TileContainerBase<PaddingType: DefaultValuing>: Control where Padding
//append all children that are accessible
items.append(contentsOf: elements)
return items
}
set {}
@ -337,7 +339,7 @@ open class TileContainerBase<PaddingType: DefaultValuing>: Control where Padding
//--------------------------------------------------
// MARK: - Public Methods
//--------------------------------------------------
/// This will place a view within the contentView of this component.
public func addContentView(_ view: UIView, shouldPin: Bool = true) {
view.removeFromSuperview()
@ -346,7 +348,7 @@ open class TileContainerBase<PaddingType: DefaultValuing>: Control where Padding
view.pinToSuperView()
}
}
//--------------------------------------------------
// MARK: - Private Methods
//--------------------------------------------------
@ -379,55 +381,10 @@ open class TileContainerBase<PaddingType: DefaultValuing>: Control where Padding
containerView.backgroundColor = color.withAlphaComponent(alphaConfiguration)
}
}
private func ratioSize(for width: CGFloat) -> CGSize {
var height: CGFloat = width
switch aspectRatio {
case .ratio1x1:
break;
case .ratio3x4:
height = (4 / 3) * width
case .ratio4x3:
height = (3 / 4) * width
case .ratio2x3:
height = (3 / 2) * width
case .ratio3x2:
height = (2 / 3) * width
case .ratio9x16:
height = (16 / 9) * width
case .ratio16x9:
height = (9 / 16) * width
case .ratio1x2:
height = (2 / 1) * width
case .ratio2x1:
height = (1 / 2) * width
default:
break
}
return CGSize(width: width, height: height)
}
private func sizeContainerView(width: CGFloat? = nil, height: CGFloat? = nil) {
if let width, width > 0 {
widthConstraint?.constant = width
widthConstraint?.activate()
}
if let height, height > 0 {
heightConstraint?.constant = height
heightConstraint?.activate()
}
}
private func updateContainerView() {
applyBackgroundEffects()
widthConstraint?.deactivate()
heightConstraint?.deactivate()
if showDropShadow, surface == .light {
containerView.addDropShadow(dropShadowConfiguration)
} else {
@ -436,50 +393,100 @@ open class TileContainerBase<PaddingType: DefaultValuing>: Control where Padding
containerView.dropShadowLayers?.forEach { $0.frame = containerView.bounds }
containerView.gradientLayers?.forEach { $0.frame = containerView.bounds }
//sizing the container with constraints
//Set local vars
var containerViewWidth: CGFloat? = width
let containerViewHeight: CGFloat? = height
let multiplier = aspectRatio.multiplier
if width != nil || height != nil {
var containerViewWidth: CGFloat?
var containerViewHeight: CGFloat?
//run logic to determine which to activate
if let width, aspectRatio == .none && height == nil{
containerViewWidth = width
} else if let height, aspectRatio == .none && width == nil{
containerViewHeight = height
} else if let height, let width {
containerViewWidth = width
containerViewHeight = height
} else if let width {
let size = ratioSize(for: width)
containerViewWidth = size.width
containerViewHeight = size.height
//turn off the constraints
aspectRatioConstraint?.deactivate()
widthConstraint?.deactivate()
heightConstraint?.deactivate()
} else if let height {
let size = ratioSize(for: height)
containerViewWidth = size.width
containerViewHeight = size.height
}
sizeContainerView(width: containerViewWidth, height: containerViewHeight)
} else {
if let parentSize = horizontalPinnedSize() {
var containerViewWidth: CGFloat?
var containerViewHeight: CGFloat?
let size = ratioSize(for: parentSize.width)
if aspectRatio == .none {
containerViewWidth = size.width
} else {
containerViewWidth = size.width
containerViewHeight = size.height
}
sizeContainerView(width: containerViewWidth, height: containerViewHeight)
}
//-------------------------------------------------------------------------
//Overriding Nil Width Rules
//-------------------------------------------------------------------------
//Rule 1:
//In the scenario where we only have a height but the multiplie is nil, we
//want to set the width with the parent's width which will more or less "fill"
//the container horizontally
//- height is set
//- width is not set
//- aspectRatio is not set
if let superviewWidth, superviewWidth > 0,
containerViewHeight != nil,
containerViewWidth == nil,
multiplier == nil {
containerViewWidth = superviewWidth
}
//Rule 2:
//In the scenario where no width and height is set, want to set the width with the
//parent's width which will more or less "fill" the container horizontally
//- height is not set
//- width is not set
else if let superviewWidth, superviewWidth > 0,
containerViewWidth == nil,
containerViewHeight == nil {
containerViewWidth = superviewWidth
}
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
//Width + AspectRatio Constraint - Will exit out if set
//-------------------------------------------------------------------------
if let containerViewWidth,
let multiplier,
containerViewWidth > 0,
containerViewHeight == nil {
widthConstraint?.constant = containerViewWidth
widthConstraint?.activate()
aspectRatioConstraint = heightAnchor.constraint(equalTo: widthAnchor, multiplier: multiplier)
aspectRatioConstraint?.activate()
return
}
//-------------------------------------------------------------------------
//Height + AspectRatio Constraint - Will exit out if set
//-------------------------------------------------------------------------
else if let containerViewHeight,
let multiplier,
containerViewHeight > 0,
containerViewWidth == nil {
heightConstraint?.constant = containerViewHeight
heightConstraint?.activate()
aspectRatioConstraint = widthAnchor.constraint(equalTo: heightAnchor, multiplier: multiplier)
aspectRatioConstraint?.activate()
return
}
//-------------------------------------------------------------------------
//Width Constraint
//-------------------------------------------------------------------------
if let containerViewWidth,
containerViewWidth > 0 {
widthConstraint?.constant = containerViewWidth
widthConstraint?.activate()
}
//-------------------------------------------------------------------------
//Height Constraint
//-------------------------------------------------------------------------
if let containerViewHeight,
containerViewHeight > 0 {
heightConstraint?.constant = containerViewHeight
heightConstraint?.activate()
}
}
/// This is the size of the superview's allowed space for this container first by constrained size which would include padding/inset values an
private var superviewWidth: CGFloat? {
horizontalPinnedWidth() ?? superview?.frame.size.width
}
}
extension TileContainerBase {
@ -519,3 +526,30 @@ extension TileContainerBase {
}
}
}
extension TileContainerBase.AspectRatio {
var multiplier: CGFloat? {
switch self {
case .ratio1x1:
return 1
case .ratio3x4:
return 4 / 3
case .ratio4x3:
return 3 / 4
case .ratio2x3:
return 3 / 2
case .ratio3x2:
return 2 / 3
case .ratio9x16:
return 16 / 9
case .ratio16x9:
return 9 / 16
case .ratio1x2:
return 2 / 1
case .ratio2x1:
return 1 / 2
case .none:
return nil
}
}
}