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
- [x] TextField
- [X] Snackbar
- [x] TabBar
- [x] Tabs
- [X] SearchBar
- [x] NavigationController
- [x] NavigationDrawer
......
......@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>2.9.1</string>
<string>2.9.2</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
......
......@@ -266,7 +266,6 @@ fileprivate extension ChipBar {
/// Prepares the scroll view.
func prepareScrollView() {
scrollView.isPagingEnabled = false
scrollView.showsVerticalScrollIndicator = false
scrollView.showsHorizontalScrollIndicator = false
centerViews = [scrollView]
......
......@@ -72,9 +72,6 @@ public enum TabBarStyle: Int {
}
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.
fileprivate var tabItemsTotalWidth: CGFloat {
var w: CGFloat = 0
......@@ -233,6 +230,7 @@ fileprivate extension TabBar {
line.zPosition = 10000
lineColor = Color.blue.base
lineHeight = 3
scrollView.addSubview(line)
}
/// Prepares the divider.
......@@ -269,10 +267,8 @@ fileprivate extension TabBar {
/// Prepares the scroll view.
func prepareScrollView() {
scrollView.isPagingEnabled = false
scrollView.showsVerticalScrollIndicator = false
scrollView.showsHorizontalScrollIndicator = false
scrollView.addSubview(line)
centerViews = [scrollView]
}
}
......@@ -324,7 +320,9 @@ fileprivate extension TabBar {
line.animate(.duration(0),
.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 {
}
selectedTabItem = tabItem
isAnimating = true
line.animate(.duration(0.25),
.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
guard let s = self else {
return
}
s.isAnimating = false
if isTriggeredByUserInteraction {
s.delegate?.tabBar?(tabBar: s, didSelect: tabItem)
}
......
......@@ -36,7 +36,6 @@ fileprivate var TabItemKey: UInt8 = 0
public enum TabBarAlignment: Int {
case top
case bottom
case hidden
}
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
display the rootViewController to the full view
......@@ -80,19 +79,13 @@ open class TabBarController: UIViewController {
@IBInspectable
open let tabBar = TabBar()
@IBInspectable
public let container = UIView()
/// An Array of UIViewControllers.
open var viewControllers: [UIViewController] {
didSet {
oldValue.forEach { [weak self] in
self?.removeViewController(viewController: $0)
}
selectedIndex = 0
prepareRootViewController()
prepareTabBar()
prepareContainer()
prepareViewControllers()
layoutSubviews()
}
}
......@@ -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.
- Parameter aDecoder: A NSCoder instance.
......@@ -130,6 +120,11 @@ open class TabBarController: UIViewController {
super.init(nibName: nil, bundle: nil)
}
fileprivate override init(rootViewController: UIViewController) {
self.viewControllers = []
super.init(rootViewController: rootViewController)
}
open override func viewDidLoad() {
super.viewDidLoad()
prepare()
......@@ -140,62 +135,33 @@ open class TabBarController: UIViewController {
layoutSubviews()
}
/**
To execute in the order of the layout chain, override this
method. `layoutSubviews` should be called immediately, unless you
have a certain need.
*/
open func layoutSubviews() {
open override func layoutSubviews() {
super.layoutSubviews()
layoutTabBar()
layoutContainer()
layoutViewController(at: selectedIndex)
}
/**
Prepares the view instance when intialized. When subclassing,
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() {
open override func prepare() {
super.prepare()
view.backgroundColor = .white
view.contentScaleFactor = Screen.scale
prepareViewControllers()
prepareTabBar()
prepareTabBarItems()
prepareContainer()
prepareViewControllers()
}
}
fileprivate extension TabBarController {
/// Prepares the container view.
func prepareContainer() {
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
internal extension TabBarController {
override func prepareRootViewController() {
rootViewController = viewControllers[selectedIndex]
}
/// Prepares all the view controllers.
}
fileprivate extension TabBarController {
/// Prepares all the view controllers.
func prepareViewControllers() {
for i in 0..<viewControllers.count {
guard i != selectedIndex else {
......@@ -207,6 +173,7 @@ fileprivate extension TabBarController {
}
prepareViewController(at: selectedIndex)
prepareRootViewController()
}
/**
......@@ -215,26 +182,39 @@ fileprivate extension TabBarController {
- Parameter at index: An Int for the viewControllers index.
*/
func prepareViewController(at index: Int) {
let vc = viewControllers[index]
let v = viewControllers[index]
guard !childViewControllers.contains(vc) else {
guard !childViewControllers.contains(v) else {
return
}
addChildViewController(vc)
vc.didMove(toParentViewController: self)
vc.isMotionEnabled = true
vc.view.clipsToBounds = true
vc.view.contentScaleFactor = Screen.scale
container.addSubview(vc.view)
prepare(viewController: v, in: 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
}
}
fileprivate extension TabBarController {
/// Layout the container.
func layoutContainer() {
tabBar.width = view.width
switch displayStyle {
case .partial:
let p = tabBar.height
......@@ -247,9 +227,6 @@ fileprivate extension TabBarController {
case .bottom:
container.y = 0
container.height = y
case .hidden:
container.y = 0
container.height = view.height
}
container.width = view.width
......@@ -261,43 +238,19 @@ fileprivate extension TabBarController {
/// Layout the tabBar.
func layoutTabBar() {
tabBar.x = 0
tabBar.y = .top == tabBarAlignment ? 0 : view.height - tabBar.height
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.
func layoutViewController(at index: Int) {
viewControllers[index].view.frame.size = container.bounds.size
rootViewController.view.frame = container.bounds
}
}
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.
- Parameter at index: An Int for the view controller position.
*/
......@@ -323,26 +276,12 @@ fileprivate extension TabBarController {
return
}
let fvc = viewControllers[selectedIndex]
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
transition(to: viewControllers[i]) { [weak self] (isFinished) in
guard isFinished else {
return
}
s.selectedIndex = i
self?.selectedIndex = i
}
}
}
......@@ -79,6 +79,7 @@ open class TransitionController: UIViewController {
}
/// A reference to the container view.
@IBInspectable
open let container = UIView()
/**
......@@ -87,7 +88,7 @@ open class TransitionController: UIViewController {
is recommended to use the transitionFromRootViewController
helper method.
*/
open fileprivate(set) var rootViewController: UIViewController!
open internal(set) var rootViewController: UIViewController!
/// The transition type used during a transition.
open var motionTransitionType = MotionTransitionType.fade
......@@ -137,10 +138,14 @@ open class TransitionController: UIViewController {
to the toViewController has completed.
*/
open func transition(to viewController: UIViewController, completion: ((Bool) -> Void)? = nil) {
let fvc = rootViewController!
guard let fvc = rootViewController else {
return
}
let tvc = viewController
tvc.view.frame.size = view.bounds.size
tvc.view.isHidden = false
tvc.view.frame = view.bounds
tvc.motionModalTransitionType = motionTransitionType
view.isUserInteractionEnabled = false
......@@ -183,6 +188,7 @@ internal extension TransitionController {
/// Prepares the container view.
func prepareContainer() {
container.frame = view.bounds
container.clipsToBounds = true
container.contentScaleFactor = Screen.scale
container.autoresizingMask = [.flexibleWidth, .flexibleHeight]
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