TabView: Animations when closing tabs as well

This commit is contained in:
James Magahern
2021-02-15 18:13:38 -08:00
parent 09c6204a73
commit dbe1377df9
3 changed files with 37 additions and 19 deletions

View File

@@ -257,6 +257,9 @@ class BrowserViewController: UIViewController, WKNavigationDelegate, WKUIDelegat
self.tab = tab self.tab = tab
} }
} }
// Show tab bar view?
browserView.tabBarViewVisible = tabController.tabs.count > 1
}) })
self.view = browserView self.view = browserView
@@ -307,9 +310,6 @@ class BrowserViewController: UIViewController, WKNavigationDelegate, WKUIDelegat
// Autocomplete view // Autocomplete view
browserView.autocompleteView = autocompleteViewController.view browserView.autocompleteView = autocompleteViewController.view
// Show tab bar view?
browserView.tabBarViewVisible = tabController.tabs.count > 1
// Color theme // Color theme
browserView.titlebarView.setColorTheme(tab.colorTheme) browserView.titlebarView.setColorTheme(tab.colorTheme)

View File

@@ -11,6 +11,8 @@ class TabView: UIControl
{ {
var active: Bool = false { didSet { setNeedsLayout() } } var active: Bool = false { didSet { setNeedsLayout() } }
var collapsed: Bool = false var collapsed: Bool = false
var identifier: UUID?
let label = UILabel(frame: .zero) let label = UILabel(frame: .zero)
let closeButton = UIButton(frame: .zero) let closeButton = UIButton(frame: .zero)
let imageView = UIImageView(image: nil) let imageView = UIImageView(image: nil)
@@ -104,6 +106,7 @@ protocol TabBarViewDataSource: AnyObject {
func numberOfTabs(forTabBarView: TabBarView) -> Int func numberOfTabs(forTabBarView: TabBarView) -> Int
func tabBarView(_ tabBarView: TabBarView, titleForTabAtIndex: Int) -> String func tabBarView(_ tabBarView: TabBarView, titleForTabAtIndex: Int) -> String
func tabBarView(_ tabBarView: TabBarView, imageForTabAtIndex: Int) -> UIImage? func tabBarView(_ tabBarView: TabBarView, imageForTabAtIndex: Int) -> UIImage?
func tabBarView(_ tabBarView: TabBarView, uniqueIdentifierForTabAtIndex: Int) -> UUID
} }
protocol TabBarViewDelegate: AnyObject { protocol TabBarViewDelegate: AnyObject {
@@ -143,29 +146,36 @@ class TabBarView: UIView
public func reloadTabs(animated: Bool = true) { public func reloadTabs(animated: Bool = true) {
guard let dataSource = self.dataSource else { return } guard let dataSource = self.dataSource else { return }
let numberOfTabs = dataSource.numberOfTabs(forTabBarView: self) var tabViewsRemoved = Set<TabView>(tabViews)
while numberOfTabs < tabViews.count {
let tabView = tabViews.removeLast()
tabView.removeFromSuperview()
}
while numberOfTabs > tabViews.count { let numberOfTabs = dataSource.numberOfTabs(forTabBarView: self)
let newTabView = makeTabView() 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 } if animated { newTabView.collapsed = true }
tabViews.append(newTabView) tabViews.append(newTabView)
} }
for (i, _) in tabViews.enumerated() {
self.reloadTab(atIndex: i)
} }
layoutSubviews() layoutSubviews()
if animated { if animated {
// Incoming tabs uncollapse
tabViews.forEach { $0.collapsed = false } 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() layoutSubviews()
} }, completion: { [unowned self] finished in
tabViewsRemoved.forEach { $0.removeFromSuperview() }
tabViews.removeAll { tabViewsRemoved.contains($0) }
})
} }
// Adjust scroll offset // Adjust scroll offset
@@ -190,8 +200,10 @@ class TabBarView: UIView
setNeedsLayout() setNeedsLayout()
} }
private func makeTabView() -> TabView { private func makeTabView(withIdentifier identifier: UUID) -> TabView {
let tabView = TabView() let tabView = TabView()
tabView.identifier = identifier
tabView.addAction(UIAction(handler: { [unowned self, tabView] _ in tabView.addAction(UIAction(handler: { [unowned self, tabView] _ in
guard let delegate = self.delegate else { return } guard let delegate = self.delegate else { return }
guard let tabIndex = self.tabViews.firstIndex(of: tabView) 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() { for (i, tabView) in tabViews.enumerated() {
tabContainerView.addSubview(tabView) tabContainerView.addSubview(tabView)
tabView.alpha = tabView.collapsed ? 0.0 : 1.0
tabView.frame = CGRect( tabView.frame = CGRect(
x: xOffset, x: xOffset,
y: tabContainerBounds.minY, y: tabContainerBounds.minY,

View File

@@ -71,4 +71,8 @@ class TabBarViewController: UIViewController, TabBarViewDataSource, TabBarViewDe
tabController.tabs[index].favicon tabController.tabs[index].favicon
} }
func tabBarView(_ tabBarView: TabBarView, uniqueIdentifierForTabAtIndex index: Int) -> UUID {
tabController.tabs[index].identifier
}
} }