614 lines
25 KiB
Swift
614 lines
25 KiB
Swift
//
|
|
// Tilet.swift
|
|
// VDS
|
|
//
|
|
// Created by Matt Bruce on 12/19/22.
|
|
//
|
|
|
|
import Foundation
|
|
import Foundation
|
|
import VDSCoreTokens
|
|
import UIKit
|
|
import Combine
|
|
|
|
/// Tilelet can be configured with a background image and limited text to
|
|
/// support quick scanning and engagement. A Tilelet is fully clickable and
|
|
/// while it can include an arrow CTA, it does not require one in order to
|
|
/// function.
|
|
@objc(VDSTilelet)
|
|
open class Tilelet: TileContainerBase<Tilelet.Padding> {
|
|
|
|
/// Enum used to describe the padding choices used for this component.
|
|
public enum Padding: String, DefaultValuing, CaseIterable {
|
|
case small
|
|
case large
|
|
|
|
public static var defaultValue: Self { .large }
|
|
|
|
public var value: CGFloat {
|
|
switch self {
|
|
case .small:
|
|
return UIDevice.isIPad ? VDSLayout.space3X : VDSLayout.space4X
|
|
case .large:
|
|
return UIDevice.isIPad ? VDSLayout.space4X : VDSLayout.space6X
|
|
}
|
|
}
|
|
|
|
fileprivate var titleLockupBottomSpacing: CGFloat {
|
|
switch self.value {
|
|
case VDSLayout.space3X:
|
|
return VDSLayout.space4X
|
|
case VDSLayout.space4X:
|
|
return VDSLayout.space6X
|
|
case VDSLayout.space4X:
|
|
return VDSLayout.space8X
|
|
default:
|
|
return VDSLayout.space4X
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//--------------------------------------------------
|
|
// MARK: - Initializers
|
|
//--------------------------------------------------
|
|
required public init() {
|
|
super.init(frame: .zero)
|
|
}
|
|
|
|
public override init(frame: CGRect) {
|
|
super.init(frame: .zero)
|
|
}
|
|
|
|
public required init?(coder: NSCoder) {
|
|
super.init(coder: coder)
|
|
}
|
|
|
|
//--------------------------------------------------
|
|
// MARK: - Enums
|
|
//--------------------------------------------------
|
|
/// Enum to represent the Vertical Layout of the Text.
|
|
public enum TextPosition: String, CaseIterable {
|
|
case top
|
|
case middle
|
|
case bottom
|
|
}
|
|
|
|
/// Enum to represent the Width of the Text.
|
|
public enum TextWidth {
|
|
case value(CGFloat)
|
|
case percentage(CGFloat)
|
|
}
|
|
//--------------------------------------------------
|
|
// MARK: - Private Properties
|
|
//--------------------------------------------------
|
|
private var stackView = UIStackView().with {
|
|
$0.translatesAutoresizingMaskIntoConstraints = false
|
|
$0.axis = .vertical
|
|
$0.distribution = .fill
|
|
$0.spacing = 5
|
|
}
|
|
|
|
private var titleLockupContainerView = UIView().with {
|
|
$0.translatesAutoresizingMaskIntoConstraints = false
|
|
}
|
|
|
|
private var badgeContainerView = UIView().with {
|
|
$0.translatesAutoresizingMaskIntoConstraints = false
|
|
}
|
|
|
|
private let iconContainerView = UIView().with {
|
|
$0.translatesAutoresizingMaskIntoConstraints = false
|
|
$0.backgroundColor = .clear
|
|
}
|
|
|
|
private var backgroundColorSurface: Surface {
|
|
backgroundColorConfiguration.getColor(self).surface
|
|
}
|
|
|
|
//--------------------------------------------------
|
|
// MARK: - Public Properties
|
|
//--------------------------------------------------
|
|
/// Title lockup positioned in the contentView.
|
|
open var titleLockup = TitleLockup().with {
|
|
$0.standardStyleConfiguration = .init(styleConfigurations: [
|
|
.init(deviceType: .iPhone,
|
|
titleStandardStyles: [.bodySmall],
|
|
spacingConfigurations: [
|
|
.init(otherStandardStyles: [.bodySmall],
|
|
topSpacing: VDSLayout.space1X,
|
|
bottomSpacing: VDSLayout.space1X)
|
|
]),
|
|
.init(deviceType: .iPhone,
|
|
titleStandardStyles: [.bodyMedium],
|
|
spacingConfigurations: [
|
|
.init(otherStandardStyles: [.bodyMedium],
|
|
topSpacing: VDSLayout.space1X,
|
|
bottomSpacing: VDSLayout.space1X)
|
|
]),
|
|
.init(deviceType: .iPhone,
|
|
titleStandardStyles: [.bodyLarge],
|
|
spacingConfigurations: [
|
|
.init(otherStandardStyles: [.bodyLarge],
|
|
topSpacing: VDSLayout.space1X,
|
|
bottomSpacing: VDSLayout.space1X)
|
|
]),
|
|
.init(deviceType: .iPhone,
|
|
titleStandardStyles: [.titleSmall],
|
|
spacingConfigurations: [
|
|
.init(otherStandardStyles: [.bodySmall, .bodyMedium],
|
|
topSpacing: VDSLayout.space2X,
|
|
bottomSpacing: VDSLayout.space2X)
|
|
]),
|
|
.init(deviceType: .iPhone,
|
|
titleStandardStyles: [.titleMedium, .titleLarge],
|
|
spacingConfigurations: [
|
|
.init(otherStandardStyles: [.bodySmall, .bodyMedium, .bodyLarge],
|
|
topSpacing: VDSLayout.space2X,
|
|
bottomSpacing: VDSLayout.space2X)
|
|
]),
|
|
.init(deviceType: .iPhone,
|
|
titleStandardStyles: [.titleXLarge],
|
|
spacingConfigurations: [
|
|
.init(otherStandardStyles: [.bodyLarge, .bodySmall, .bodyMedium, .titleMedium],
|
|
topSpacing: VDSLayout.space3X,
|
|
bottomSpacing: VDSLayout.space3X)
|
|
]),
|
|
.init(deviceType: .iPad,
|
|
titleStandardStyles: [.bodySmall],
|
|
spacingConfigurations: [
|
|
.init(otherStandardStyles: [.bodySmall],
|
|
topSpacing: VDSLayout.space2X,
|
|
bottomSpacing: VDSLayout.space2X)
|
|
]),
|
|
.init(deviceType: .iPad,
|
|
titleStandardStyles: [.bodyMedium],
|
|
spacingConfigurations: [
|
|
.init(otherStandardStyles: [.bodyMedium],
|
|
topSpacing: VDSLayout.space1X,
|
|
bottomSpacing: VDSLayout.space1X)
|
|
]),
|
|
.init(deviceType: .iPad,
|
|
titleStandardStyles: [.bodyLarge],
|
|
spacingConfigurations: [
|
|
.init(otherStandardStyles: [.bodyLarge],
|
|
topSpacing: VDSLayout.space1X,
|
|
bottomSpacing: VDSLayout.space1X)
|
|
]),
|
|
.init(deviceType: .iPad,
|
|
titleStandardStyles: [.titleSmall, .titleMedium],
|
|
spacingConfigurations: [
|
|
.init(otherStandardStyles: [.bodySmall, .bodyMedium, .bodyLarge],
|
|
topSpacing: VDSLayout.space2X,
|
|
bottomSpacing: VDSLayout.space2X)
|
|
]),
|
|
.init(deviceType: .iPad,
|
|
titleStandardStyles: [.titleLarge],
|
|
spacingConfigurations: [
|
|
.init(otherStandardStyles: [.bodyLarge, .bodySmall, .bodyMedium, .titleSmall],
|
|
topSpacing: VDSLayout.space3X,
|
|
bottomSpacing: VDSLayout.space3X)
|
|
]),
|
|
.init(deviceType: .iPad,
|
|
titleStandardStyles: [.titleXLarge],
|
|
spacingConfigurations: [
|
|
.init(otherStandardStyles: [.titleMedium, .bodyLarge],
|
|
topSpacing: VDSLayout.space3X,
|
|
bottomSpacing: VDSLayout.space4X)
|
|
])
|
|
])
|
|
}
|
|
|
|
/// Badge positioned in the contentView.
|
|
open var badge = Badge().with {
|
|
$0.fillColor = .red
|
|
}
|
|
|
|
/// Descriptive Icon positioned in the contentView.
|
|
open var descriptiveIcon = Icon().with {
|
|
$0.isAccessibilityElement = false
|
|
}
|
|
|
|
/// Directional Icon positioned in the contentView.
|
|
open var directionalIcon = Icon().with {
|
|
$0.isAccessibilityElement = false
|
|
$0.name = .rightArrow
|
|
}
|
|
|
|
private var _textWidth: TextWidth?
|
|
|
|
/// If provided, width of Button components will be rendered based on this value. If omitted, default button widths are rendered.
|
|
open var textWidth: TextWidth? {
|
|
get { _textWidth }
|
|
set {
|
|
if let newValue {
|
|
switch newValue {
|
|
case .percentage(let percentage):
|
|
if percentage >= 10 && percentage <= 100.0 {
|
|
_textWidth = newValue
|
|
}
|
|
case .value(let value):
|
|
if value > 44.0 {
|
|
_textWidth = newValue
|
|
}
|
|
}
|
|
} else {
|
|
_textWidth = nil
|
|
}
|
|
setNeedsUpdate()
|
|
}
|
|
}
|
|
|
|
/// Determines where the text aligns vertically.
|
|
open var textPostion: TextPosition = .top { didSet { setNeedsUpdate() } }
|
|
|
|
/// If set, this is used to render the badge.
|
|
open var badgeModel: BadgeModel? { didSet { setNeedsUpdate() } }
|
|
|
|
/// If set, this is used to render the titleLabel of the TitleLockup.
|
|
open var titleModel: TitleModel? { didSet { setNeedsUpdate() } }
|
|
|
|
/// If set, this is used to render the subTitleLabel of the TitleLockup.
|
|
open var subTitleModel: SubTitleModel? { didSet { setNeedsUpdate() } }
|
|
|
|
/// If set, this is used to render the eyebrowLabel of the TitleLockup.
|
|
open var eyebrowModel: EyebrowModel? { didSet { setNeedsUpdate() } }
|
|
|
|
//only 1 Icon can be active
|
|
private var _descriptiveIconModel: DescriptiveIcon?
|
|
|
|
/// If set, this is used to render the descriptive icon.
|
|
open var descriptiveIconModel: DescriptiveIcon? {
|
|
get { _descriptiveIconModel }
|
|
set {
|
|
_descriptiveIconModel = newValue;
|
|
_directionalIconModel = nil
|
|
setNeedsUpdate()
|
|
}
|
|
}
|
|
|
|
private var _directionalIconModel: DirectionalIcon?
|
|
|
|
/// If set, this is used to render the directional icon.
|
|
open var directionalIconModel: DirectionalIcon? {
|
|
get { _directionalIconModel }
|
|
set {
|
|
_directionalIconModel = newValue;
|
|
_descriptiveIconModel = nil
|
|
setNeedsUpdate()
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------
|
|
// MARK: - Constraints
|
|
//--------------------------------------------------
|
|
internal var titleLockupWidthConstraint: NSLayoutConstraint?
|
|
internal var titleLockupTrailingConstraint: NSLayoutConstraint?
|
|
internal var titleLockupTopConstraint: NSLayoutConstraint?
|
|
internal var titleLockupBottomConstraint: NSLayoutConstraint?
|
|
internal var titleLockupTopGreaterThanConstraint: NSLayoutConstraint?
|
|
internal var titleLockupBottomGreaterThanConstraint: NSLayoutConstraint?
|
|
internal var titleLockupCenterYConstraint: NSLayoutConstraint?
|
|
internal var titleLockupTitleLabelBottomConstraint: NSLayoutConstraint?
|
|
//Truncation constraints
|
|
internal var badgeLabelHeightGreaterThanConstraint: NSLayoutConstraint?
|
|
internal var titleLockupEyebrowLabelHeightGreaterThanConstraint: NSLayoutConstraint?
|
|
internal var titleLockupTitleLabelHeightGreaterThanConstraint: NSLayoutConstraint?
|
|
internal var titleLockupSubTitleLabelHeightGreaterThanConstraint: NSLayoutConstraint?
|
|
|
|
//--------------------------------------------------
|
|
// MARK: - Overrides
|
|
//--------------------------------------------------
|
|
/// Called once when a view is initialized and is used to Setup additional UI or other constants and configurations.
|
|
open override func setup() {
|
|
super.setup()
|
|
color = .black
|
|
aspectRatio = .none
|
|
|
|
addContentView(stackView)
|
|
|
|
//badge
|
|
badgeContainerView.addSubview(badge)
|
|
badge
|
|
.pinTop()
|
|
.pinLeading()
|
|
.pinBottom()
|
|
badge.trailingAnchor.constraint(lessThanOrEqualTo: badgeContainerView.trailingAnchor).isActive = true
|
|
|
|
titleLockupContainerView.addSubview(titleLockup)
|
|
titleLockup
|
|
.pinLeading()
|
|
titleLockupTopConstraint = titleLockup.topAnchor.constraint(equalTo: titleLockupContainerView.topAnchor)
|
|
titleLockupTopConstraint?.activate()
|
|
titleLockupBottomConstraint = titleLockupContainerView.bottomAnchor.constraint(equalTo: titleLockup.bottomAnchor)
|
|
titleLockupBottomConstraint?.activate()
|
|
titleLockupTrailingConstraint = titleLockup.trailingAnchor.constraint(equalTo: titleLockupContainerView.trailingAnchor)
|
|
titleLockupTrailingConstraint?.activate()
|
|
titleLockupBottomGreaterThanConstraint = titleLockupContainerView.bottomAnchor.constraint(greaterThanOrEqualTo: titleLockup.bottomAnchor)
|
|
titleLockupTopGreaterThanConstraint = titleLockup.topAnchor.constraint(greaterThanOrEqualTo: titleLockupContainerView.topAnchor)
|
|
titleLockupCenterYConstraint = titleLockup.centerYAnchor.constraint(equalTo: titleLockupContainerView.centerYAnchor)
|
|
|
|
iconContainerView.addSubview(descriptiveIcon)
|
|
iconContainerView.addSubview(directionalIcon)
|
|
|
|
descriptiveIcon
|
|
.pinLeading()
|
|
.pinTop()
|
|
.pinBottom()
|
|
|
|
directionalIcon
|
|
.pinTrailing()
|
|
.pinTop()
|
|
.pinBottom()
|
|
|
|
badge.bottomAnchor.constraint(equalTo: badge.label.bottomAnchor, constant: 2).activate()
|
|
|
|
/**
|
|
Truncation:
|
|
If a Tilelet has only a Title or a Subtitle, then the Title or Subtitle is truncated and appended with an ellipsis when there is not enough space to display the full text.
|
|
If a Tilelet has both Title and Subtitle, then only Subtitle will be truncated.
|
|
If a Tilelet has Badge, Title and Subtitle, then Subtitle will be truncated first and Badge will be truncated second. Title will be truncated last (lowest priority).
|
|
Atleast one line text based on priority
|
|
Minimum bottom space below Badge is 4px; less than 4px results in truncation.
|
|
*/
|
|
let labelPriority = UILayoutPriority.defaultHigh.rawValue
|
|
titleLockup.titleLabel.setContentCompressionResistancePriority(UILayoutPriority(labelPriority), for: .vertical)
|
|
badge.label.setContentCompressionResistancePriority(UILayoutPriority(labelPriority-1), for: .vertical)
|
|
titleLockup.subTitleLabel.setContentCompressionResistancePriority(UILayoutPriority(labelPriority-2), for: .vertical)
|
|
titleLockup.eyebrowLabel.setContentCompressionResistancePriority(UILayoutPriority(labelPriority-3), for: .vertical)
|
|
|
|
titleLockup.titleLabel.setContentHuggingPriority(UILayoutPriority(labelPriority), for: .vertical)
|
|
badge.label.setContentHuggingPriority(UILayoutPriority(labelPriority-1), for: .vertical)
|
|
titleLockup.subTitleLabel.setContentHuggingPriority(UILayoutPriority(labelPriority-2), for: .vertical)
|
|
titleLockup.eyebrowLabel.setContentHuggingPriority(UILayoutPriority(labelPriority-3), for: .vertical)
|
|
|
|
/**
|
|
Added these constraints for:
|
|
At fixed width & height if all the labels(Badge, Eyebrow, Title, Subtitle) are having more number of lines then we should display atleast one line of content per label instead of pushing labels out of bounds.
|
|
So adding minimum single line height constraint
|
|
*/
|
|
badgeLabelHeightGreaterThanConstraint = badge.label.heightGreaterThanEqualTo(constant: badge.label.minimumLineHeight)
|
|
badgeLabelHeightGreaterThanConstraint?.priority = .defaultHigh
|
|
badgeLabelHeightGreaterThanConstraint?.activate()
|
|
|
|
titleLockupEyebrowLabelHeightGreaterThanConstraint = titleLockup.eyebrowLabel.heightGreaterThanEqualTo(constant: titleLockup.eyebrowLabel.minimumLineHeight)
|
|
titleLockupEyebrowLabelHeightGreaterThanConstraint?.priority = .defaultHigh
|
|
titleLockupEyebrowLabelHeightGreaterThanConstraint?.activate()
|
|
|
|
titleLockupTitleLabelHeightGreaterThanConstraint = titleLockup.titleLabel.heightGreaterThanEqualTo(constant: titleLockup.titleLabel.minimumLineHeight)
|
|
titleLockupTitleLabelHeightGreaterThanConstraint?.priority = .defaultHigh
|
|
titleLockupTitleLabelHeightGreaterThanConstraint?.activate()
|
|
|
|
titleLockupSubTitleLabelHeightGreaterThanConstraint = titleLockup.subTitleLabel.heightGreaterThanEqualTo(constant: titleLockup.subTitleLabel.minimumLineHeight)
|
|
titleLockupSubTitleLabelHeightGreaterThanConstraint?.priority = .defaultHigh
|
|
titleLockupSubTitleLabelHeightGreaterThanConstraint?.activate()
|
|
}
|
|
|
|
/// Resets to default settings.
|
|
open override func reset() {
|
|
shouldUpdateView = false
|
|
super.reset()
|
|
aspectRatio = .none
|
|
color = .black
|
|
//models
|
|
badgeModel = nil
|
|
titleModel = nil
|
|
subTitleModel = nil
|
|
descriptiveIconModel = nil
|
|
directionalIconModel = nil
|
|
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()
|
|
|
|
updateBadge()
|
|
updateTitleLockup()
|
|
updateIcons()
|
|
updateTextPositionAlignment()
|
|
setNeedsLayout()
|
|
}
|
|
|
|
/// Used to update any Accessibility properties.
|
|
open override var accessibilityElements: [Any]? {
|
|
get {
|
|
var views = [UIView]()
|
|
|
|
// grab the available views in order
|
|
if badgeModel != nil {
|
|
views.append(badge)
|
|
}
|
|
|
|
if titleModel != nil || subTitleModel != nil || eyebrowModel != nil {
|
|
views.append(titleLockup)
|
|
}
|
|
|
|
containerView.setAccessibilityLabel(for: views)
|
|
|
|
// get the views to return
|
|
var items = [Any]()
|
|
if containerView.isAccessibilityElement {
|
|
if !accessibilityTraits.contains(.button) && !accessibilityTraits.contains(.link) {
|
|
containerView.accessibilityTraits = .button
|
|
} else {
|
|
containerView.accessibilityTraits = accessibilityTraits
|
|
}
|
|
items.append(containerView)
|
|
}
|
|
|
|
//append all other accessible views to traverse
|
|
items.append(contentsOf: views)
|
|
|
|
return items
|
|
}
|
|
set {}
|
|
}
|
|
|
|
//--------------------------------------------------
|
|
// MARK: - Private Methods
|
|
//--------------------------------------------------
|
|
private func updateBadge() {
|
|
if let badgeModel {
|
|
badge.text = badgeModel.text
|
|
badge.fillColor = badgeModel.fillColor
|
|
badge.numberOfLines = badgeModel.numberOfLines
|
|
badge.surface = backgroundColorSurface
|
|
badge.maxWidth = badgeModel.maxWidth
|
|
badgeLabelHeightGreaterThanConstraint?.constant = badge.label.minimumLineHeight
|
|
if badgeContainerView.superview == nil {
|
|
stackView.insertArrangedSubview(badgeContainerView, at: 0)
|
|
setNeedsLayout()
|
|
}
|
|
} else {
|
|
removeFromSuperview(badgeContainerView)
|
|
}
|
|
}
|
|
|
|
private func updateTitleLockup() {
|
|
|
|
var showTitleLockup = false
|
|
|
|
if let eyebrowModel, !eyebrowModel.text.isEmpty {
|
|
showTitleLockup = true
|
|
}
|
|
|
|
if let titleModel, !titleModel.text.isEmpty {
|
|
showTitleLockup = true
|
|
}
|
|
|
|
if let subTitleModel, !subTitleModel.text.isEmpty {
|
|
showTitleLockup = true
|
|
}
|
|
|
|
if showTitleLockup {
|
|
//flip the surface for the titleLockup
|
|
titleLockup.surface = backgroundColorSurface
|
|
|
|
//titleLockup
|
|
if let textWidth {
|
|
titleLockupTrailingConstraint?.isActive = false
|
|
titleLockupTrailingConstraint = titleLockup.trailingAnchor.constraint(lessThanOrEqualTo: titleLockupContainerView.trailingAnchor)
|
|
titleLockupTrailingConstraint?.isActive = true
|
|
|
|
titleLockupWidthConstraint?.isActive = false
|
|
|
|
switch textWidth {
|
|
case .value(let value):
|
|
titleLockupWidthConstraint = titleLockup.widthAnchor.constraint(equalToConstant: value)
|
|
case .percentage(let percentage):
|
|
titleLockupWidthConstraint = NSLayoutConstraint(item: titleLockup,
|
|
attribute: .width,
|
|
relatedBy: .equal,
|
|
toItem: contentView,
|
|
attribute: .width,
|
|
multiplier: percentage / 100,
|
|
constant: 0.0)
|
|
}
|
|
|
|
titleLockupWidthConstraint?.isActive = true
|
|
|
|
} else {
|
|
titleLockupTrailingConstraint?.isActive = false
|
|
titleLockupTrailingConstraint = titleLockup.trailingAnchor.constraint(equalTo: titleLockupContainerView.trailingAnchor)
|
|
titleLockupTrailingConstraint?.isActive = true
|
|
titleLockupWidthConstraint?.isActive = false
|
|
}
|
|
|
|
//set models
|
|
titleLockup.eyebrowModel = eyebrowModel?.toTitleLockupEyebrowModel()
|
|
titleLockup.titleModel = titleModel?.toTitleLockupTitleModel()
|
|
titleLockup.subTitleModel = subTitleModel?.toTitleLockupSubTitleModel()
|
|
|
|
if titleLockupContainerView.superview == nil {
|
|
stackView.insertArrangedSubview(titleLockupContainerView, at: badgeContainerView.superview == nil ? 0 : 1)
|
|
setNeedsLayout()
|
|
}
|
|
} else {
|
|
removeFromSuperview(titleLockupContainerView)
|
|
}
|
|
titleLockupEyebrowLabelHeightGreaterThanConstraint?.constant = titleLockup.eyebrowLabel.minimumLineHeight
|
|
titleLockupTitleLabelHeightGreaterThanConstraint?.constant = titleLockup.titleLabel.minimumLineHeight
|
|
titleLockupSubTitleLabelHeightGreaterThanConstraint?.constant = titleLockup.subTitleLabel.minimumLineHeight
|
|
}
|
|
|
|
private func updateIcons() {
|
|
//icons
|
|
var showIconContainerView = false
|
|
if let descriptiveIconModel {
|
|
descriptiveIcon.name = descriptiveIconModel.name
|
|
if let color = descriptiveIconModel.iconColor?.uiColor {
|
|
descriptiveIcon.color = color
|
|
}
|
|
descriptiveIcon.size = descriptiveIconModel.size
|
|
descriptiveIcon.surface = backgroundColorSurface
|
|
showIconContainerView = true
|
|
}
|
|
|
|
if let directionalIconModel {
|
|
directionalIcon.name = directionalIconModel.iconType.iconName
|
|
if let color = directionalIconModel.iconColor?.uiColor {
|
|
directionalIcon.color = color
|
|
}
|
|
directionalIcon.size = directionalIconModel.size.value
|
|
directionalIcon.surface = backgroundColorSurface
|
|
showIconContainerView = true
|
|
}
|
|
|
|
//iconContainer
|
|
descriptiveIcon.isHidden = descriptiveIconModel == nil
|
|
directionalIcon.isHidden = directionalIconModel == nil
|
|
|
|
if showIconContainerView {
|
|
//spacing before iconContainerView
|
|
var view: UIView?
|
|
if badgeContainerView.superview != nil {
|
|
view = badgeContainerView
|
|
}
|
|
if titleLockupContainerView.superview != nil {
|
|
view = titleLockupContainerView
|
|
}
|
|
if let view {
|
|
stackView.setCustomSpacing(padding.titleLockupBottomSpacing, after: view)
|
|
}
|
|
if iconContainerView.superview == nil {
|
|
stackView.addArrangedSubview(iconContainerView)
|
|
setNeedsDisplay()
|
|
}
|
|
} else {
|
|
removeFromSuperview(iconContainerView)
|
|
}
|
|
}
|
|
|
|
private func updateTextPositionAlignment() {
|
|
guard width != nil && (aspectRatio != .none || height != nil) else { return }
|
|
switch textPostion {
|
|
case .top:
|
|
titleLockupTopConstraint?.activate()
|
|
titleLockupTopGreaterThanConstraint?.deactivate()
|
|
titleLockupBottomConstraint?.deactivate()
|
|
titleLockupBottomGreaterThanConstraint?.activate()
|
|
titleLockupCenterYConstraint?.deactivate()
|
|
case .middle:
|
|
titleLockupTopConstraint?.deactivate()
|
|
titleLockupTopGreaterThanConstraint?.activate()
|
|
titleLockupBottomConstraint?.deactivate()
|
|
titleLockupBottomGreaterThanConstraint?.activate()
|
|
titleLockupCenterYConstraint?.activate()
|
|
case .bottom:
|
|
titleLockupTopConstraint?.deactivate()
|
|
titleLockupTopGreaterThanConstraint?.activate()
|
|
titleLockupBottomConstraint?.activate()
|
|
titleLockupBottomGreaterThanConstraint?.deactivate()
|
|
titleLockupCenterYConstraint?.deactivate()
|
|
}
|
|
}
|
|
}
|
|
|
|
extension Label {
|
|
|
|
///To calculate label single line height
|
|
fileprivate var minimumLineHeight: CGFloat { textStyle.lineHeight }
|
|
}
|