Commit 360d7223 by Daniel Dahan

rework of TabBarController with now subclassing TransitionController

parent d1bb7442
...@@ -35,7 +35,6 @@ Take a look at [Sample Projects](https://github.com/CosmicMind/Samples) to get y ...@@ -35,7 +35,6 @@ Take a look at [Sample Projects](https://github.com/CosmicMind/Samples) to get y
- [x] TextField - [x] TextField
- [X] Snackbar - [X] Snackbar
- [x] TabBar - [x] TabBar
- [x] Tabs
- [X] SearchBar - [X] SearchBar
- [x] NavigationController - [x] NavigationController
- [x] NavigationDrawer - [x] NavigationDrawer
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>FMWK</string> <string>FMWK</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>2.9.1</string> <string>2.9.2</string>
<key>CFBundleSignature</key> <key>CFBundleSignature</key>
<string>????</string> <string>????</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
......
...@@ -266,7 +266,6 @@ fileprivate extension ChipBar { ...@@ -266,7 +266,6 @@ fileprivate extension ChipBar {
/// Prepares the scroll view. /// Prepares the scroll view.
func prepareScrollView() { func prepareScrollView() {
scrollView.isPagingEnabled = false
scrollView.showsVerticalScrollIndicator = false scrollView.showsVerticalScrollIndicator = false
scrollView.showsHorizontalScrollIndicator = false scrollView.showsHorizontalScrollIndicator = false
centerViews = [scrollView] centerViews = [scrollView]
......
...@@ -72,9 +72,6 @@ public enum TabBarStyle: Int { ...@@ -72,9 +72,6 @@ public enum TabBarStyle: Int {
} }
open class TabBar: Bar { open class TabBar: Bar {
/// A boolean indicating if the TabBar is in an animation state.
open fileprivate(set) var isAnimating = false
/// The total width of the tabItems. /// The total width of the tabItems.
fileprivate var tabItemsTotalWidth: CGFloat { fileprivate var tabItemsTotalWidth: CGFloat {
var w: CGFloat = 0 var w: CGFloat = 0
...@@ -233,6 +230,7 @@ fileprivate extension TabBar { ...@@ -233,6 +230,7 @@ fileprivate extension TabBar {
line.zPosition = 10000 line.zPosition = 10000
lineColor = Color.blue.base lineColor = Color.blue.base
lineHeight = 3 lineHeight = 3
scrollView.addSubview(line)
} }
/// Prepares the divider. /// Prepares the divider.
...@@ -269,10 +267,8 @@ fileprivate extension TabBar { ...@@ -269,10 +267,8 @@ fileprivate extension TabBar {
/// Prepares the scroll view. /// Prepares the scroll view.
func prepareScrollView() { func prepareScrollView() {
scrollView.isPagingEnabled = false
scrollView.showsVerticalScrollIndicator = false scrollView.showsVerticalScrollIndicator = false
scrollView.showsHorizontalScrollIndicator = false scrollView.showsHorizontalScrollIndicator = false
scrollView.addSubview(line)
centerViews = [scrollView] centerViews = [scrollView]
} }
} }
...@@ -324,7 +320,9 @@ fileprivate extension TabBar { ...@@ -324,7 +320,9 @@ fileprivate extension TabBar {
line.animate(.duration(0), line.animate(.duration(0),
.size(CGSize(width: v.width, height: lineHeight)), .size(CGSize(width: v.width, height: lineHeight)),
.position(CGPoint(x: v.center.x, y: .bottom == lineAlignment ? height - lineHeight / 2 : lineHeight / 2))) .position(CGPoint(x: v.x + v.width / 2, y: .bottom == lineAlignment ? height - lineHeight / 2 : lineHeight / 2)))
// line.frame = CGRect(x: v.x, y: .bottom == lineAlignment ? scrollView.height - lineHeight : 0, width: v.width, height: lineHeight)
} }
} }
...@@ -384,18 +382,14 @@ fileprivate extension TabBar { ...@@ -384,18 +382,14 @@ fileprivate extension TabBar {
} }
selectedTabItem = tabItem selectedTabItem = tabItem
isAnimating = true
line.animate(.duration(0.25), line.animate(.duration(0.25),
.size(CGSize(width: tabItem.width, height: lineHeight)), .size(CGSize(width: tabItem.width, height: lineHeight)),
.position(CGPoint(x: tabItem.center.x, y: .bottom == lineAlignment ? height - lineHeight / 2 : lineHeight / 2)), .position(CGPoint(x: tabItem.x + tabItem.width / 2, y: .bottom == lineAlignment ? height - lineHeight / 2 : lineHeight / 2)),
.completion { [weak self, isTriggeredByUserInteraction = isTriggeredByUserInteraction, tabItem = tabItem, completion = completion] _ in .completion { [weak self, isTriggeredByUserInteraction = isTriggeredByUserInteraction, tabItem = tabItem, completion = completion] _ in
guard let s = self else { guard let s = self else {
return return
} }
s.isAnimating = false
if isTriggeredByUserInteraction { if isTriggeredByUserInteraction {
s.delegate?.tabBar?(tabBar: s, didSelect: tabItem) s.delegate?.tabBar?(tabBar: s, didSelect: tabItem)
} }
......
...@@ -36,7 +36,6 @@ fileprivate var TabItemKey: UInt8 = 0 ...@@ -36,7 +36,6 @@ fileprivate var TabItemKey: UInt8 = 0
public enum TabBarAlignment: Int { public enum TabBarAlignment: Int {
case top case top
case bottom case bottom
case hidden
} }
extension UIViewController { extension UIViewController {
...@@ -64,7 +63,7 @@ extension UIViewController { ...@@ -64,7 +63,7 @@ extension UIViewController {
} }
} }
open class TabBarController: UIViewController { open class TabBarController: TransitionController {
/** /**
A Display value to indicate whether or not to A Display value to indicate whether or not to
display the rootViewController to the full view display the rootViewController to the full view
...@@ -80,19 +79,13 @@ open class TabBarController: UIViewController { ...@@ -80,19 +79,13 @@ open class TabBarController: UIViewController {
@IBInspectable @IBInspectable
open let tabBar = TabBar() open let tabBar = TabBar()
@IBInspectable
public let container = UIView()
/// An Array of UIViewControllers. /// An Array of UIViewControllers.
open var viewControllers: [UIViewController] { open var viewControllers: [UIViewController] {
didSet { didSet {
oldValue.forEach { [weak self] in selectedIndex = 0
self?.removeViewController(viewController: $0)
}
prepareRootViewController()
prepareTabBar() prepareTabBar()
prepareContainer()
prepareViewControllers()
layoutSubviews() layoutSubviews()
} }
} }
...@@ -108,9 +101,6 @@ open class TabBarController: UIViewController { ...@@ -108,9 +101,6 @@ open class TabBarController: UIViewController {
} }
} }
/// The transition type used during a transition.
open var motionTransitionType = MotionTransitionType.fade
/** /**
An initializer that initializes the object with a NSCoder object. An initializer that initializes the object with a NSCoder object.
- Parameter aDecoder: A NSCoder instance. - Parameter aDecoder: A NSCoder instance.
...@@ -130,6 +120,11 @@ open class TabBarController: UIViewController { ...@@ -130,6 +120,11 @@ open class TabBarController: UIViewController {
super.init(nibName: nil, bundle: nil) super.init(nibName: nil, bundle: nil)
} }
fileprivate override init(rootViewController: UIViewController) {
self.viewControllers = []
super.init(rootViewController: rootViewController)
}
open override func viewDidLoad() { open override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
prepare() prepare()
...@@ -140,62 +135,33 @@ open class TabBarController: UIViewController { ...@@ -140,62 +135,33 @@ open class TabBarController: UIViewController {
layoutSubviews() layoutSubviews()
} }
/** open override func layoutSubviews() {
To execute in the order of the layout chain, override this super.layoutSubviews()
method. `layoutSubviews` should be called immediately, unless you
have a certain need.
*/
open func layoutSubviews() {
layoutTabBar() layoutTabBar()
layoutContainer() layoutContainer()
layoutViewController(at: selectedIndex) layoutViewController(at: selectedIndex)
} }
/** open override func prepare() {
Prepares the view instance when intialized. When subclassing, super.prepare()
it is recommended to override the prepare method
to initialize property values and other setup operations.
The super.prepare method should always be called immediately
when subclassing.
*/
open func prepare() {
view.backgroundColor = .white view.backgroundColor = .white
view.contentScaleFactor = Screen.scale view.contentScaleFactor = Screen.scale
prepareViewControllers()
prepareTabBar() prepareTabBar()
prepareTabBarItems() prepareTabBarItems()
prepareContainer()
prepareViewControllers()
} }
} }
fileprivate extension TabBarController { internal extension TabBarController {
/// Prepares the container view. override func prepareRootViewController() {
func prepareContainer() { rootViewController = viewControllers[selectedIndex]
view.addSubview(container)
}
/// Prepares the TabBar.
func prepareTabBar() {
tabBar.lineAlignment = .bottom == tabBarAlignment ? .top : .bottom
view.addSubview(tabBar)
}
/// Prepares the `tabBar.tabItems`.
func prepareTabBarItems() {
var tabItems = [TabItem]()
for v in viewControllers {
let b = v.tabItem
b.removeTarget(self, action: #selector(handle(tabItem:)), for: .touchUpInside)
b.addTarget(self, action: #selector(handle(tabItem:)), for: .touchUpInside)
tabItems.append(b)
}
tabBar.tabItems = tabItems
} }
}
/// Prepares all the view controllers.
fileprivate extension TabBarController {
/// Prepares all the view controllers.
func prepareViewControllers() { func prepareViewControllers() {
for i in 0..<viewControllers.count { for i in 0..<viewControllers.count {
guard i != selectedIndex else { guard i != selectedIndex else {
...@@ -207,6 +173,7 @@ fileprivate extension TabBarController { ...@@ -207,6 +173,7 @@ fileprivate extension TabBarController {
} }
prepareViewController(at: selectedIndex) prepareViewController(at: selectedIndex)
prepareRootViewController()
} }
/** /**
...@@ -215,26 +182,39 @@ fileprivate extension TabBarController { ...@@ -215,26 +182,39 @@ fileprivate extension TabBarController {
- Parameter at index: An Int for the viewControllers index. - Parameter at index: An Int for the viewControllers index.
*/ */
func prepareViewController(at index: Int) { func prepareViewController(at index: Int) {
let vc = viewControllers[index] let v = viewControllers[index]
guard !childViewControllers.contains(vc) else { guard !childViewControllers.contains(v) else {
return return
} }
addChildViewController(vc) prepare(viewController: v, in: container)
vc.didMove(toParentViewController: self) }
vc.isMotionEnabled = true
vc.view.clipsToBounds = true /// Prepares the TabBar.
vc.view.contentScaleFactor = Screen.scale func prepareTabBar() {
container.addSubview(vc.view) tabBar.lineAlignment = .bottom == tabBarAlignment ? .top : .bottom
view.addSubview(tabBar)
}
/// Prepares the `tabBar.tabItems`.
func prepareTabBarItems() {
var tabItems = [TabItem]()
for v in viewControllers {
let b = v.tabItem
b.removeTarget(self, action: #selector(handle(tabItem:)), for: .touchUpInside)
b.addTarget(self, action: #selector(handle(tabItem:)), for: .touchUpInside)
tabItems.append(b)
}
tabBar.tabItems = tabItems
} }
} }
fileprivate extension TabBarController { fileprivate extension TabBarController {
/// Layout the container. /// Layout the container.
func layoutContainer() { func layoutContainer() {
tabBar.width = view.width
switch displayStyle { switch displayStyle {
case .partial: case .partial:
let p = tabBar.height let p = tabBar.height
...@@ -247,9 +227,6 @@ fileprivate extension TabBarController { ...@@ -247,9 +227,6 @@ fileprivate extension TabBarController {
case .bottom: case .bottom:
container.y = 0 container.y = 0
container.height = y container.height = y
case .hidden:
container.y = 0
container.height = view.height
} }
container.width = view.width container.width = view.width
...@@ -261,43 +238,19 @@ fileprivate extension TabBarController { ...@@ -261,43 +238,19 @@ fileprivate extension TabBarController {
/// Layout the tabBar. /// Layout the tabBar.
func layoutTabBar() { func layoutTabBar() {
tabBar.x = 0
tabBar.y = .top == tabBarAlignment ? 0 : view.height - tabBar.height
tabBar.width = view.width tabBar.width = view.width
switch tabBarAlignment {
case .top:
tabBar.isHidden = false
tabBar.y = 0
case .bottom:
tabBar.isHidden = false
tabBar.y = view.height - tabBar.height
case .hidden:
tabBar.isHidden = true
}
} }
/// Layout the view controller at the given index. /// Layout the view controller at the given index.
func layoutViewController(at index: Int) { func layoutViewController(at index: Int) {
viewControllers[index].view.frame.size = container.bounds.size rootViewController.view.frame = container.bounds
} }
} }
fileprivate extension TabBarController { fileprivate extension TabBarController {
/** /**
Removes the view controller as a child view controller with
the given index.
- Parameter at index: An Int for the view controller position.
*/
func removeViewController(at index: Int) {
let v = viewControllers[index]
guard childViewControllers.contains(v) else {
return
}
removeViewController(viewController: v)
}
/**
Removes a given view controller from the childViewControllers array. Removes a given view controller from the childViewControllers array.
- Parameter at index: An Int for the view controller position. - Parameter at index: An Int for the view controller position.
*/ */
...@@ -323,26 +276,12 @@ fileprivate extension TabBarController { ...@@ -323,26 +276,12 @@ fileprivate extension TabBarController {
return return
} }
let fvc = viewControllers[selectedIndex] transition(to: viewControllers[i]) { [weak self] (isFinished) in
let tvc = viewControllers[i]
tvc.view.isHidden = false
tvc.view.frame.size = container.bounds.size
tvc.motionModalTransitionType = motionTransitionType
view.isUserInteractionEnabled = false
Motion.shared.transition(from: fvc, to: tvc, in: container) { [weak self] (isFinished) in
guard let s = self else {
return
}
s.view.isUserInteractionEnabled = true
guard isFinished else { guard isFinished else {
return return
} }
s.selectedIndex = i self?.selectedIndex = i
} }
} }
} }
...@@ -79,6 +79,7 @@ open class TransitionController: UIViewController { ...@@ -79,6 +79,7 @@ open class TransitionController: UIViewController {
} }
/// A reference to the container view. /// A reference to the container view.
@IBInspectable
open let container = UIView() open let container = UIView()
/** /**
...@@ -87,7 +88,7 @@ open class TransitionController: UIViewController { ...@@ -87,7 +88,7 @@ open class TransitionController: UIViewController {
is recommended to use the transitionFromRootViewController is recommended to use the transitionFromRootViewController
helper method. helper method.
*/ */
open fileprivate(set) var rootViewController: UIViewController! open internal(set) var rootViewController: UIViewController!
/// The transition type used during a transition. /// The transition type used during a transition.
open var motionTransitionType = MotionTransitionType.fade open var motionTransitionType = MotionTransitionType.fade
...@@ -137,10 +138,14 @@ open class TransitionController: UIViewController { ...@@ -137,10 +138,14 @@ open class TransitionController: UIViewController {
to the toViewController has completed. to the toViewController has completed.
*/ */
open func transition(to viewController: UIViewController, completion: ((Bool) -> Void)? = nil) { open func transition(to viewController: UIViewController, completion: ((Bool) -> Void)? = nil) {
let fvc = rootViewController! guard let fvc = rootViewController else {
return
}
let tvc = viewController let tvc = viewController
tvc.view.frame.size = view.bounds.size tvc.view.isHidden = false
tvc.view.frame = view.bounds
tvc.motionModalTransitionType = motionTransitionType tvc.motionModalTransitionType = motionTransitionType
view.isUserInteractionEnabled = false view.isUserInteractionEnabled = false
...@@ -183,6 +188,7 @@ internal extension TransitionController { ...@@ -183,6 +188,7 @@ internal extension TransitionController {
/// Prepares the container view. /// Prepares the container view.
func prepareContainer() { func prepareContainer() {
container.frame = view.bounds container.frame = view.bounds
container.clipsToBounds = true
container.contentScaleFactor = Screen.scale container.contentScaleFactor = Screen.scale
container.autoresizingMask = [.flexibleWidth, .flexibleHeight] container.autoresizingMask = [.flexibleWidth, .flexibleHeight]
view.addSubview(container) view.addSubview(container)
......
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