refactored tabs for bugs

Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
This commit is contained in:
Matt Bruce 2023-08-10 15:12:32 -05:00
parent 33062b4b98
commit 4c60e4907c

View File

@ -57,13 +57,13 @@ open class Tabs: View {
open var onTabChange: ((Int) -> Void)? open var onTabChange: ((Int) -> Void)?
//Determines the layout of the Tabs, defaults to horizontal //Determines the layout of the Tabs, defaults to horizontal
open var orientation: Orientation = .horizontal { didSet { if oldValue != orientation { updateTabItems() } } } open var orientation: Orientation = .horizontal { didSet { if oldValue != orientation { setNeedsUpdate() } } }
///When true, Tabs will have border line. If false is passed then the border line won't be visible. ///When true, Tabs will have border line. If false is passed then the border line won't be visible.
open var borderLine: Bool = true { didSet { setNeedsUpdate() } } open var borderLine: Bool = true { didSet { setNeedsUpdate() } }
///It will fill the Tabs to the width of the compoent and all Tabs will be in equal width when orientation is horizontal. This is recommended when there are no more than 2-3 tabs. ///It will fill the Tabs to the width of the compoent and all Tabs will be in equal width when orientation is horizontal. This is recommended when there are no more than 2-3 tabs.
open var fillContainer: Bool = false { didSet { updateTabItems() } } open var fillContainer: Bool = false { didSet { setNeedsUpdate() } }
///When true, Tabs will be sticky to top of page, when orientation is vertical. ///When true, Tabs will be sticky to top of page, when orientation is vertical.
open var indicatorFillTab: Bool = false { didSet { setNeedsUpdate() } } open var indicatorFillTab: Bool = false { didSet { setNeedsUpdate() } }
@ -75,13 +75,13 @@ open class Tabs: View {
open var minWidth: CGFloat = 44.0 { didSet { setNeedsUpdate() } } open var minWidth: CGFloat = 44.0 { didSet { setNeedsUpdate() } }
///If set to 'scroll', Tabs can be overflow and scrollable. With 'none', tabs will not overflow and labels will be wrapped to multiple lines if the label text is long. ///If set to 'scroll', Tabs can be overflow and scrollable. With 'none', tabs will not overflow and labels will be wrapped to multiple lines if the label text is long.
open var overflow: Overflow = .scroll { didSet { updateTabItems() } } open var overflow: Overflow = .scroll { didSet { setNeedsUpdate() } }
///The initial Selected Tab's index and is set once a Tab is clicked ///The initial Selected Tab's index and is set once a Tab is clicked
open var selectedIndex: Int = 0 { didSet { setNeedsUpdate() } } open var selectedIndex: Int = 0 { didSet { setNeedsUpdate() } }
///Determines the size of the Tabs TextStyle ///Determines the size of the Tabs TextStyle
open var size: Size = .medium { didSet { updateTabItems() } } open var size: Size = .medium { didSet { setNeedsUpdate() } }
///When true, Tabs will be sticky to top of page, when orientation is vertical. ///When true, Tabs will be sticky to top of page, when orientation is vertical.
open var sticky: Bool = false { didSet { setNeedsUpdate() } } open var sticky: Bool = false { didSet { setNeedsUpdate() } }
@ -123,7 +123,7 @@ open class Tabs: View {
if orientation == .horizontal && fillContainer { if orientation == .horizontal && fillContainer {
return .fillEqually return .fillEqually
} else { } else {
return orientation == .horizontal ? .fillProportionally : .fill return .fill //orientation == .horizontal ? .fillProportionally : .fill
} }
} }
@ -184,6 +184,7 @@ open class Tabs: View {
scrollView.pinToSuperView() scrollView.pinToSuperView()
contentView.pinToSuperView() contentView.pinToSuperView()
tabStackView.pinToSuperView() tabStackView.pinToSuperView()
contentView.heightAnchor.constraint(equalTo: scrollView.heightAnchor).isActive = true contentView.heightAnchor.constraint(equalTo: scrollView.heightAnchor).isActive = true
borderlineViewWidthConstraint = borderlineView.widthAnchor.constraint(equalToConstant: 0) borderlineViewWidthConstraint = borderlineView.widthAnchor.constraint(equalToConstant: 0)
@ -196,18 +197,29 @@ open class Tabs: View {
} }
private func updateTabItems() { /// Function used to make changes to the View based off a change events or from local properties.
updateTabItems(with: tabModels) open override func updateView() {
super.updateView()
updateStackView()
updateTabs()
updateContentView()
updateBorderline()
} }
private func updateTabItems(with models: [TabModel]) { //--------------------------------------------------
// MARK: - Private Methods
//--------------------------------------------------
/// Removes all of the Tab Views and creates new ones from the Tab Models property.
private func updateTabItems() {
// Clear existing tab items // Clear existing tab items
for tabItem in tabViews { for tabItem in tabViews {
tabItem.removeFromSuperview() tabItem.removeFromSuperview()
} }
tabViews.removeAll() tabViews.removeAll()
// Create new tab items from the models // Create new tab items from the models
for model in models { for model in tabModels {
let tabItem = Tab() let tabItem = Tab()
tabItem.size = size tabItem.size = size
tabItem.text = model.text tabItem.text = model.text
@ -225,6 +237,9 @@ open class Tabs: View {
scrollToSelectedIndex(animated: false) scrollToSelectedIndex(animated: false)
} }
/// Scrolls to the selected Tab by the selectedIndex.
/// - Parameter animated: If there is animation of the scrolling to the selectedIndex.
private func scrollToSelectedIndex(animated: Bool) { private func scrollToSelectedIndex(animated: Bool) {
if orientation == .horizontal && self.overflow == .scroll, selectedIndex < tabViews.count { if orientation == .horizontal && self.overflow == .scroll, selectedIndex < tabViews.count {
let selectedTab = tabViews[selectedIndex] let selectedTab = tabViews[selectedIndex]
@ -232,17 +247,17 @@ open class Tabs: View {
} }
} }
/// Function used to make changes to the View based off a change events or from local properties.
open override func updateView() {
super.updateView()
// Update the stackview properties /// Updates the StackView from local properties.
private func updateStackView() {
tabStackView.distribution = stackViewDistribution tabStackView.distribution = stackViewDistribution
tabStackView.axis = stackViewAxis tabStackView.axis = stackViewAxis
tabStackView.alignment = stackViewAlignment tabStackView.alignment = stackViewAlignment
tabStackView.spacing = stackViewSpacing tabStackView.spacing = stackViewSpacing
}
// Update tab appearance based on properties /// Updates the Tab individual views from local properties.
private func updateTabs() {
for (index, tabItem) in tabViews.enumerated() { for (index, tabItem) in tabViews.enumerated() {
tabItem.size = size tabItem.size = size
tabItem.isSelected = selectedIndex == index tabItem.isSelected = selectedIndex == index
@ -254,14 +269,9 @@ open class Tabs: View {
tabItem.indicatorPosition = indicatorPosition tabItem.indicatorPosition = indicatorPosition
tabItem.accessibilityValue = "\(index+1) of \(tabViews.count) Tabs" tabItem.accessibilityValue = "\(index+1) of \(tabViews.count) Tabs"
} }
//update the width based on rules
updateContentView()
setNeedsLayout()
layoutIfNeeded()
} }
// Update the ContentView and ScrollView ContentSize from local properties.
private func updateContentView() { private func updateContentView() {
// Deactivate old constraint // Deactivate old constraint
contentViewWidthConstraint?.isActive = false contentViewWidthConstraint?.isActive = false
@ -269,10 +279,10 @@ open class Tabs: View {
// Apply overflow // Apply overflow
if orientation == .horizontal && overflow == .scroll && !fillContainer { if orientation == .horizontal && overflow == .scroll && !fillContainer {
let contentWidth = tabStackView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize).width let contentWidth = tabStackView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize).width
contentViewWidthConstraint = contentView.widthAnchor.constraint(equalToConstant: contentWidth) contentViewWidthConstraint = nil
scrollView.contentSize = CGSize(width: contentWidth, height: scrollView.bounds.height) scrollView.contentSize = CGSize(width: contentWidth, height: scrollView.bounds.height)
} else { } else {
contentViewWidthConstraint = contentView.widthAnchor.constraint(equalTo: widthAnchor) contentViewWidthConstraint = contentView.widthAnchor.constraint(equalTo: scrollView.widthAnchor)
scrollView.contentSize = bounds.size scrollView.contentSize = bounds.size
} }
@ -284,9 +294,8 @@ open class Tabs: View {
scrollToSelectedIndex(animated: true) scrollToSelectedIndex(animated: true)
} }
open override func layoutSubviews() { //update layout for borderline
super.layoutSubviews() private func updateBorderline() {
//borderLine //borderLine
if borderLine { if borderLine {
var edge: UIRectEdge = .bottom var edge: UIRectEdge = .bottom
@ -330,4 +339,6 @@ open class Tabs: View {
borderlineView.isHidden = true borderlineView.isHidden = true
} }
} }
} }