Commit 6554f20e by Daniel Dahan

development: fixed grid issue, where views were causing an out of bounds index error

parent 8363fcbd
...@@ -91,29 +91,15 @@ open class ControlView: View { ...@@ -91,29 +91,15 @@ open class ControlView: View {
open private(set) var contentView: View! open private(set) var contentView: View!
/// Left side UIControls. /// Left side UIControls.
open var leftControls: [UIView] { open var leftControls = [UIView]() {
didSet { didSet {
for v in oldValue { layoutSubviews()
v.removeFromSuperview()
}
for v in leftControls {
addSubview(v)
}
layoutSubviews()
} }
} }
/// Right side UIControls. /// Right side UIControls.
open var rightControls: [UIView] { open var rightControls = [UIView]() {
didSet { didSet {
for v in oldValue {
v.removeFromSuperview()
}
for v in rightControls {
addSubview(v)
}
layoutSubviews() layoutSubviews()
} }
} }
...@@ -123,8 +109,6 @@ open class ControlView: View { ...@@ -123,8 +109,6 @@ open class ControlView: View {
- Parameter aDecoder: A NSCoder instance. - Parameter aDecoder: A NSCoder instance.
*/ */
public required init?(coder aDecoder: NSCoder) { public required init?(coder aDecoder: NSCoder) {
leftControls = []
rightControls = []
super.init(coder: aDecoder) super.init(coder: aDecoder)
} }
...@@ -135,15 +119,11 @@ open class ControlView: View { ...@@ -135,15 +119,11 @@ open class ControlView: View {
- Parameter frame: A CGRect instance. - Parameter frame: A CGRect instance.
*/ */
public override init(frame: CGRect) { public override init(frame: CGRect) {
leftControls = [] super.init(frame: frame)
rightControls = []
super.init(frame: frame)
} }
/// Basic initializer. /// Basic initializer.
public init() { public init() {
leftControls = []
rightControls = []
super.init(frame: .zero) super.init(frame: .zero)
frame.size = intrinsicContentSize frame.size = intrinsicContentSize
} }
......
...@@ -173,7 +173,7 @@ public class Grid { ...@@ -173,7 +173,7 @@ public class Grid {
} }
/// An Array of UIButtons. /// An Array of UIButtons.
public var views: [UIView] { public var views = [UIView]() {
didSet { didSet {
reload() reload()
} }
...@@ -190,7 +190,6 @@ public class Grid { ...@@ -190,7 +190,6 @@ public class Grid {
self.rows = rows self.rows = rows
self.columns = columns self.columns = columns
self.interimSpace = interimSpace self.interimSpace = interimSpace
views = [UIView]()
offset = GridOffset(grid: self) offset = GridOffset(grid: self)
axis = GridAxis(grid: self) axis = GridAxis(grid: self)
} }
...@@ -198,57 +197,60 @@ public class Grid { ...@@ -198,57 +197,60 @@ public class Grid {
/// Reload the button layout. /// Reload the button layout.
public func reload() { public func reload() {
var n: Int = 0 var n: Int = 0
var i: Int = 0
for i in 0..<views.count { for child in views {
let child = views[i] guard let parent = context else {
return
}
if parent != child.superview {
child.removeFromSuperview()
parent.addSubview(child)
}
if let parent = context { parent.layoutIfNeeded()
if parent != child.superview {
child.removeFromSuperview() switch axis.direction {
parent.addSubview(child) case .horizontal:
} let c = child.grid.columns
let co = child.grid.offset.columns
let w = (parent.bounds.width - contentEdgeInsets.left - contentEdgeInsets.right - layoutEdgeInsets.left - layoutEdgeInsets.right + interimSpace) / CGFloat(axis.columns)
child.x = CGFloat(i + n + co) * w + contentEdgeInsets.left + layoutEdgeInsets.left
child.y = contentEdgeInsets.top + layoutEdgeInsets.top
child.width = w * CGFloat(c) - interimSpace
child.height = parent.bounds.height - contentEdgeInsets.top - contentEdgeInsets.bottom - layoutEdgeInsets.top - layoutEdgeInsets.bottom
parent.layoutIfNeeded() n += c + co - 1
switch axis.direction { case .vertical:
case .horizontal: let r = child.grid.rows
let c = child.grid.columns let ro = child.grid.offset.rows
let co = child.grid.offset.columns let h = (parent.bounds.height - contentEdgeInsets.top - contentEdgeInsets.bottom - layoutEdgeInsets.top - layoutEdgeInsets.bottom + interimSpace) / CGFloat(axis.rows)
let w = (parent.bounds.width - contentEdgeInsets.left - contentEdgeInsets.right - layoutEdgeInsets.left - layoutEdgeInsets.right + interimSpace) / CGFloat(axis.columns)
child.x = CGFloat(i + n + co) * w + contentEdgeInsets.left + layoutEdgeInsets.left
child.y = contentEdgeInsets.top + layoutEdgeInsets.top
child.width = w * CGFloat(c) - interimSpace
child.height = parent.bounds.height - contentEdgeInsets.top - contentEdgeInsets.bottom - layoutEdgeInsets.top - layoutEdgeInsets.bottom
n += c + co - 1
case .vertical:
let r = child.grid.rows
let ro = child.grid.offset.rows
let h = (parent.bounds.height - contentEdgeInsets.top - contentEdgeInsets.bottom - layoutEdgeInsets.top - layoutEdgeInsets.bottom + interimSpace) / CGFloat(axis.rows)
child.x = contentEdgeInsets.left + layoutEdgeInsets.left
child.y = CGFloat(i + n + ro) * h + contentEdgeInsets.top + layoutEdgeInsets.top
child.width = parent.bounds.width - contentEdgeInsets.left - contentEdgeInsets.right - layoutEdgeInsets.left - layoutEdgeInsets.right
child.height = h * CGFloat(r) - interimSpace
n += r + ro - 1
case .any: child.x = contentEdgeInsets.left + layoutEdgeInsets.left
let r = child.grid.rows child.y = CGFloat(i + n + ro) * h + contentEdgeInsets.top + layoutEdgeInsets.top
let ro = child.grid.offset.rows child.width = parent.bounds.width - contentEdgeInsets.left - contentEdgeInsets.right - layoutEdgeInsets.left - layoutEdgeInsets.right
let c = child.grid.columns child.height = h * CGFloat(r) - interimSpace
let co = child.grid.offset.columns
let w = (parent.bounds.width - contentEdgeInsets.left - contentEdgeInsets.right - layoutEdgeInsets.left - layoutEdgeInsets.right + interimSpace) / CGFloat(axis.columns) n += r + ro - 1
let h = (parent.bounds.height - contentEdgeInsets.top - contentEdgeInsets.bottom - layoutEdgeInsets.top - layoutEdgeInsets.bottom + interimSpace) / CGFloat(axis.rows)
case .any:
child.x = CGFloat(co) * w + contentEdgeInsets.left + layoutEdgeInsets.left let r = child.grid.rows
child.y = CGFloat(ro) * h + contentEdgeInsets.top + layoutEdgeInsets.top let ro = child.grid.offset.rows
child.width = w * CGFloat(c) - interimSpace let c = child.grid.columns
child.height = h * CGFloat(r) - interimSpace let co = child.grid.offset.columns
} let w = (parent.bounds.width - contentEdgeInsets.left - contentEdgeInsets.right - layoutEdgeInsets.left - layoutEdgeInsets.right + interimSpace) / CGFloat(axis.columns)
let h = (parent.bounds.height - contentEdgeInsets.top - contentEdgeInsets.bottom - layoutEdgeInsets.top - layoutEdgeInsets.bottom + interimSpace) / CGFloat(axis.rows)
child.x = CGFloat(co) * w + contentEdgeInsets.left + layoutEdgeInsets.left
child.y = CGFloat(ro) * h + contentEdgeInsets.top + layoutEdgeInsets.top
child.width = w * CGFloat(c) - interimSpace
child.height = h * CGFloat(r) - interimSpace
} }
i += 1
} }
} }
} }
......
...@@ -55,6 +55,9 @@ public protocol PageControllerDelegate { ...@@ -55,6 +55,9 @@ public protocol PageControllerDelegate {
@objc(PageController) @objc(PageController)
open class PageController: RootController { open class PageController: RootController {
/// A boolean that indicates when a button animation is active.
internal var animating = false
/// The currently selected UIViewController. /// The currently selected UIViewController.
open internal(set) var selectedIndex: Int = 0 open internal(set) var selectedIndex: Int = 0
...@@ -137,6 +140,12 @@ open class PageController: RootController { ...@@ -137,6 +140,12 @@ open class PageController: RootController {
v.delegate = self v.delegate = self
v.dataSource = self v.dataSource = self
v.isDoubleSided = false v.isDoubleSided = false
for view in v.view.subviews {
if view.isKind(of: UIScrollView.self) {
(view as? UIScrollView)?.delegate = self
}
}
} }
/// Prepares the tabBar. /// Prepares the tabBar.
...@@ -145,6 +154,7 @@ open class PageController: RootController { ...@@ -145,6 +154,7 @@ open class PageController: RootController {
tabBar = TabBar() tabBar = TabBar()
tabBar.zPosition = 1000 tabBar.zPosition = 1000
view.addSubview(tabBar) view.addSubview(tabBar)
tabBar.select(at: selectedIndex)
} }
} }
} }
...@@ -157,7 +167,25 @@ extension PageController { ...@@ -157,7 +167,25 @@ extension PageController {
} }
extension PageController: UIPageViewControllerDelegate { extension PageController: UIPageViewControllerDelegate {
public func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
guard let vc = previousViewControllers.first else {
return
}
guard let index = viewControllers.index(of: vc) else {
return
}
guard completed else {
tabBar.select(at: index) { [weak self] _ in
guard let s = self else {
return
}
s.animating = false
}
return
}
}
} }
extension PageController: UIPageViewControllerDataSource { extension PageController: UIPageViewControllerDataSource {
...@@ -190,3 +218,28 @@ extension PageController: UIPageViewControllerDataSource { ...@@ -190,3 +218,28 @@ extension PageController: UIPageViewControllerDataSource {
return viewControllers[next] return viewControllers[next]
} }
} }
extension PageController: UIScrollViewDelegate {
public func scrollViewDidScroll(_ scrollView: UIScrollView) {
guard !animating else {
return
}
let x = scrollView.contentOffset.x / scrollView.contentSize.width * scrollView.width
guard 0 < x else {
return
}
tabBar.line.x = x
print("scrolling", x)
}
public func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
// animating = true
}
public func scrollViewWillBeginDecelerating(_ scrollView: UIScrollView) {
animating = true
}
}
...@@ -185,7 +185,28 @@ open class TabBar: View { ...@@ -185,7 +185,28 @@ open class TabBar: View {
/// Handles the button touch event. /// Handles the button touch event.
@objc @objc
internal func handleButton(button: UIButton) { internal func handleButton(button: UIButton) {
delegate?.tabBarWillSelectButton?(tabBar: self, button: button) animate(to: button)
}
/**
Selects a given index from the buttons array.
- Parameter at index: An Int.
- Paramater completion: An optional completion block.
*/
open func select(at index: Int, completion: (@escaping (UIButton) -> Void)? = nil) {
guard -1 < index, index < buttons.count else {
return
}
animate(to: buttons[index], completion: completion)
}
/**
Animates to a given button.
- Parameter to button: A UIButton.
- Paramater completion: An optional completion block.
*/
internal func animate(to button: UIButton, completion: (@escaping (UIButton) -> Void)? = nil) {
delegate?.tabBarWillSelectButton?(tabBar: self, button: button)
selected = button selected = button
UIView.animate(withDuration: 0.25, animations: { [weak self, button = button] in UIView.animate(withDuration: 0.25, animations: { [weak self, button = button] in
...@@ -194,14 +215,15 @@ open class TabBar: View { ...@@ -194,14 +215,15 @@ open class TabBar: View {
} }
s.line.x = button.x s.line.x = button.x
s.line.width = button.width s.line.width = button.width
}) { [weak self, button = button] _ in }) { [weak self, button = button, completion = completion] _ in
guard let s = self else { guard let s = self else {
return return
} }
s.delegate?.tabBarDidSelectButton?(tabBar: s, button: button) s.delegate?.tabBarDidSelectButton?(tabBar: s, button: button)
completion?(button)
} }
} }
/** /**
Prepares the view instance when intialized. When subclassing, Prepares the view instance when intialized. When subclassing,
it is recommended to override the prepareView method it is recommended to override the prepareView method
......
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