TabView: Animations when closing tabs as well
This commit is contained in:
@@ -11,6 +11,8 @@ class TabView: UIControl
|
||||
{
|
||||
var active: Bool = false { didSet { setNeedsLayout() } }
|
||||
var collapsed: Bool = false
|
||||
var identifier: UUID?
|
||||
|
||||
let label = UILabel(frame: .zero)
|
||||
let closeButton = UIButton(frame: .zero)
|
||||
let imageView = UIImageView(image: nil)
|
||||
@@ -104,6 +106,7 @@ protocol TabBarViewDataSource: AnyObject {
|
||||
func numberOfTabs(forTabBarView: TabBarView) -> Int
|
||||
func tabBarView(_ tabBarView: TabBarView, titleForTabAtIndex: Int) -> String
|
||||
func tabBarView(_ tabBarView: TabBarView, imageForTabAtIndex: Int) -> UIImage?
|
||||
func tabBarView(_ tabBarView: TabBarView, uniqueIdentifierForTabAtIndex: Int) -> UUID
|
||||
}
|
||||
|
||||
protocol TabBarViewDelegate: AnyObject {
|
||||
@@ -143,29 +146,36 @@ class TabBarView: UIView
|
||||
public func reloadTabs(animated: Bool = true) {
|
||||
guard let dataSource = self.dataSource else { return }
|
||||
|
||||
var tabViewsRemoved = Set<TabView>(tabViews)
|
||||
|
||||
let numberOfTabs = dataSource.numberOfTabs(forTabBarView: self)
|
||||
while numberOfTabs < tabViews.count {
|
||||
let tabView = tabViews.removeLast()
|
||||
tabView.removeFromSuperview()
|
||||
}
|
||||
|
||||
while numberOfTabs > tabViews.count {
|
||||
let newTabView = makeTabView()
|
||||
if animated { newTabView.collapsed = true }
|
||||
tabViews.append(newTabView)
|
||||
}
|
||||
|
||||
for (i, _) in tabViews.enumerated() {
|
||||
self.reloadTab(atIndex: i)
|
||||
for i in 0..<numberOfTabs {
|
||||
let identifier = dataSource.tabBarView(self, uniqueIdentifierForTabAtIndex: i)
|
||||
if let tabView = tabViewsRemoved.first(where: { $0.identifier == identifier }) {
|
||||
tabViewsRemoved.remove(tabView)
|
||||
self.reloadTab(atIndex: i)
|
||||
} else {
|
||||
let newTabView = makeTabView(withIdentifier: identifier)
|
||||
if animated { newTabView.collapsed = true }
|
||||
tabViews.append(newTabView)
|
||||
}
|
||||
}
|
||||
|
||||
layoutSubviews()
|
||||
|
||||
if animated {
|
||||
// Incoming tabs uncollapse
|
||||
tabViews.forEach { $0.collapsed = false }
|
||||
UIView.animate(withDuration: 0.3) { [unowned self] in
|
||||
|
||||
// Outgoing tabs collapse
|
||||
tabViewsRemoved.forEach { $0.collapsed = true }
|
||||
|
||||
UIView.animate(withDuration: 0.22, delay: 0.0, usingSpringWithDamping: 1.0, initialSpringVelocity: 1.0, options: [], animations: { [unowned self] in
|
||||
layoutSubviews()
|
||||
}
|
||||
}, completion: { [unowned self] finished in
|
||||
tabViewsRemoved.forEach { $0.removeFromSuperview() }
|
||||
tabViews.removeAll { tabViewsRemoved.contains($0) }
|
||||
})
|
||||
}
|
||||
|
||||
// Adjust scroll offset
|
||||
@@ -190,8 +200,10 @@ class TabBarView: UIView
|
||||
setNeedsLayout()
|
||||
}
|
||||
|
||||
private func makeTabView() -> TabView {
|
||||
private func makeTabView(withIdentifier identifier: UUID) -> TabView {
|
||||
let tabView = TabView()
|
||||
tabView.identifier = identifier
|
||||
|
||||
tabView.addAction(UIAction(handler: { [unowned self, tabView] _ in
|
||||
guard let delegate = self.delegate else { return }
|
||||
guard let tabIndex = self.tabViews.firstIndex(of: tabView) else { return }
|
||||
@@ -244,6 +256,8 @@ class TabBarView: UIView
|
||||
for (i, tabView) in tabViews.enumerated() {
|
||||
tabContainerView.addSubview(tabView)
|
||||
|
||||
tabView.alpha = tabView.collapsed ? 0.0 : 1.0
|
||||
|
||||
tabView.frame = CGRect(
|
||||
x: xOffset,
|
||||
y: tabContainerBounds.minY,
|
||||
|
||||
Reference in New Issue
Block a user