Commit 2720a8fb by Daniel Dahan Committed by GitHub

Merge pull request #762 from 666tos/scrollable-tabbar

I am merging this into `pr-review` to test it out. Thank you!
parents d12b0cb0 ebaf45a1
...@@ -179,6 +179,10 @@ open class Bar: View { ...@@ -179,6 +179,10 @@ open class Bar: View {
open override func layoutSubviews() { open override func layoutSubviews() {
super.layoutSubviews() super.layoutSubviews()
layoutBarSubviews()
}
open func layoutBarSubviews() {
guard willLayout else { guard willLayout else {
return return
} }
......
...@@ -142,8 +142,8 @@ open class SearchBar: Bar { ...@@ -142,8 +142,8 @@ open class SearchBar: Bar {
super.init(frame: frame) super.init(frame: frame)
} }
open override func layoutSubviews() { open override func layoutBarSubviews() {
super.layoutSubviews() super.layoutBarSubviews()
guard willLayout else { guard willLayout else {
return return
} }
......
...@@ -70,8 +70,8 @@ open class Snackbar: Bar { ...@@ -70,8 +70,8 @@ open class Snackbar: Bar {
return super.hitTest(point, with: event) return super.hitTest(point, with: event)
} }
open override func layoutSubviews() { open override func layoutBarSubviews() {
super.layoutSubviews() super.layoutBarSubviews()
guard willLayout else { guard willLayout else {
return return
} }
......
...@@ -190,27 +190,93 @@ open class TabBar: Bar { ...@@ -190,27 +190,93 @@ open class TabBar: Bar {
} }
} }
open override func layoutSubviews() { open override func layoutBarSubviews() {
super.layoutSubviews()
guard willLayout else { guard willLayout else {
return return
} }
guard 0 < buttons.count else { var lc = 0
return var rc = 0
grid.begin()
grid.views.removeAll()
for v in leftViews {
if let b = v as? UIButton {
b.contentEdgeInsets = .zero
b.titleEdgeInsets = .zero
} }
for b in buttons { v.width = v.intrinsicContentSize.width
b.grid.columns = 0 v.sizeToFit()
b.cornerRadius = 0 v.grid.columns = Int(ceil(v.width / gridFactor)) + 2
lc += v.grid.columns
grid.views.append(v)
}
grid.views.append(contentView)
for v in rightViews {
if let b = v as? UIButton {
b.contentEdgeInsets = .zero b.contentEdgeInsets = .zero
b.titleEdgeInsets = .zero
}
if isLineAnimated { v.width = v.intrinsicContentSize.width
prepareLineAnimationHandler(button: b) v.sizeToFit()
v.grid.columns = Int(ceil(v.width / gridFactor)) + 2
rc += v.grid.columns
grid.views.append(v)
}
contentView.grid.begin()
contentView.grid.offset.columns = 0
var l: CGFloat = 0
var r: CGFloat = 0
if .center == contentViewAlignment {
if leftViews.count < rightViews.count {
r = CGFloat(rightViews.count) * interimSpace
l = r
} else {
l = CGFloat(leftViews.count) * interimSpace
r = l
}
}
let p = width - l - r - contentEdgeInsets.left - contentEdgeInsets.right
let columns = Int(ceil(p / gridFactor))
if .center == contentViewAlignment {
if lc < rc {
contentView.grid.columns = columns - 2 * rc
contentView.grid.offset.columns = rc - lc
} else {
contentView.grid.columns = columns - 2 * lc
rightViews.first?.grid.offset.columns = lc - rc
} }
} else {
contentView.grid.columns = columns - lc - rc
} }
if .scrollable == tabBarStyle { grid.axis.columns = columns
grid.commit()
contentView.grid.commit()
divider.reload()
let centralWidth = width - l - r
let buttonsWidth = buttons.reduce(0) { $0 + $1.sizeThatFits(CGSize(width: CGFloat.greatestFiniteMagnitude, height: contentView.height)).width + interimSpace }
let shouldScroll = (.scrollable == tabBarStyle) && (buttonsWidth > centralWidth)
if shouldScroll {
scrollView.frame = CGRect(x: l, y: 0, width: centralWidth, height: height)
var w: CGFloat = 0 var w: CGFloat = 0
for b in buttons { for b in buttons {
...@@ -222,12 +288,26 @@ open class TabBar: Bar { ...@@ -222,12 +288,26 @@ open class TabBar: Bar {
w += width w += width
} }
if w > scrollView.width { scrollView.contentSize = CGSize(width: buttonsWidth, height: height)
scrollView.contentSize.width = w scrollView.addSubview(line)
}
} else { } else {
contentView.grid.axis.columns = buttons.count contentView.grid.axis.columns = buttons.count
centerViews = buttons centerViews = buttons
addSubview(line)
}
updateSelectionLine()
}
private func updateSelectionLine() {
for b in buttons {
b.grid.columns = 0
b.cornerRadius = 0
b.contentEdgeInsets = .zero
if isLineAnimated {
prepareLineAnimationHandler(button: b)
}
} }
scrollView.frame = contentView.bounds scrollView.frame = contentView.bounds
...@@ -283,7 +363,7 @@ extension TabBar { ...@@ -283,7 +363,7 @@ extension TabBar {
fileprivate func prepareScrollView() { fileprivate func prepareScrollView() {
scrollView = UIScrollView() scrollView = UIScrollView()
scrollView.bounces = false scrollView.bounces = false
scrollView.isPagingEnabled = true scrollView.isPagingEnabled = false
scrollView.showsVerticalScrollIndicator = false scrollView.showsVerticalScrollIndicator = false
scrollView.showsHorizontalScrollIndicator = false scrollView.showsHorizontalScrollIndicator = false
contentView.addSubview(scrollView) contentView.addSubview(scrollView)
...@@ -352,6 +432,12 @@ extension TabBar { ...@@ -352,6 +432,12 @@ extension TabBar {
s.line.center.x = button.center.x s.line.center.x = button.center.x
s.line.width = button.width s.line.width = button.width
if !s.scrollView.bounds.contains(button.frame) {
let contentOffsetX = (button.x < s.scrollView.bounds.minX) ? button.x : button.frame.maxX - s.scrollView.bounds.width
let normalizedOffsetX = min(max(contentOffsetX, 0), s.scrollView.contentSize.width - s.scrollView.bounds.width)
s.scrollView.setContentOffset(CGPoint(x: normalizedOffsetX, y: 0), animated: false)
}
}) { [weak self, isTriggeredByUserInteraction = isTriggeredByUserInteraction, button = button, completion = completion] _ in }) { [weak self, isTriggeredByUserInteraction = isTriggeredByUserInteraction, button = button, completion = completion] _ in
guard let s = self else { guard let s = self else {
return return
......
...@@ -468,16 +468,17 @@ extension TabsController { ...@@ -468,16 +468,17 @@ extension TabsController {
guard i != selectedIndex else { guard i != selectedIndex else {
return return
} }
// removeViewControllers()
removeViewControllers()
// prepareViewControllersForTransition(from: selectedIndex, to: i) // prepareViewControllersForTransition(from: selectedIndex, to: i)
selectedIndex = i selectedIndex = i
v.select(at: i) v.select(at: i)
//prepareTabBar() removeViewControllers()
//layoutSubviews() prepareViewControllers()
prepareTabBar()
layoutSubviews()
} }
} }
......
...@@ -95,8 +95,8 @@ open class Toolbar: Bar { ...@@ -95,8 +95,8 @@ open class Toolbar: Bar {
contentViewAlignment = .center == titleLabel.textAlignment ? .center : .full contentViewAlignment = .center == titleLabel.textAlignment ? .center : .full
} }
open override func layoutSubviews() { open override func layoutBarSubviews() {
super.layoutSubviews() super.layoutBarSubviews()
guard willLayout else { guard willLayout else {
return return
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment