Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d30fbffb49 | |||
| 1ea19b5ce5 | |||
| d41befad6c | |||
| 7a6f0a6e49 | |||
| 0820d90917 | |||
| 7aa6ea106d | |||
| 61ede72557 | |||
| dc0869126e | |||
| db0bf49290 | |||
| 9f5c7db158 | |||
| 142c3a594d | |||
| 3227c77e97 | |||
| ccbf79db70 | |||
| 224eddc2d7 | |||
| 2eb4891a8d | |||
| 0d9eb74457 | |||
| 3f6ec80676 | |||
| 2e63da3cf4 |
@@ -1,6 +1,14 @@
|
||||
import UIKit
|
||||
import Tabby
|
||||
|
||||
class MainController: TabbyController {
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
|
||||
setIndex = 1
|
||||
}
|
||||
}
|
||||
|
||||
@UIApplicationMain
|
||||
class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
|
||||
@@ -10,8 +18,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
TabbyBarItem(controller: self.thirdNavigation, image: "fish")
|
||||
]
|
||||
|
||||
lazy var mainController: TabbyController = { [unowned self] in
|
||||
let controller = TabbyController(items: self.items)
|
||||
lazy var mainController: MainController = { [unowned self] in
|
||||
let controller = MainController(items: self.items)
|
||||
|
||||
controller.delegate = self
|
||||
controller.translucent = false
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# Tabby
|
||||
|
||||
⚠️ DEPRECATED, NO LONGER MAINTAINED
|
||||
|
||||
`// TODO: Add the image here.`
|
||||
|
||||
<div align = "center">
|
||||
@@ -17,7 +19,7 @@
|
||||
|
||||
**Tabby** is the ultimate tab bar, a full substitution for those UITabBarControllers, UITabBars and UITabBarItems that are not customizable at all. **Tabby** has animations, behaviors and it has the easiness you would expect from any of our libraries.
|
||||
|
||||
`// TODO: Add a gif here.`
|
||||

|
||||
|
||||
## Usage
|
||||
|
||||
|
||||
@@ -44,10 +44,6 @@ open class TabbyDefaultCell: UICollectionViewCell, TabbyCell {
|
||||
label.text = item.controller.title
|
||||
label.textColor = color
|
||||
|
||||
if selected {
|
||||
Constant.tapItemAnimation(imageView)
|
||||
}
|
||||
|
||||
handleBadge(count)
|
||||
handleBehaviors(selected)
|
||||
setupConstraints()
|
||||
|
||||
@@ -17,7 +17,6 @@ open class TabbyController: UIViewController, UINavigationControllerDelegate {
|
||||
|
||||
/// Used when toggling tabbyBar visibility
|
||||
private var tabbyBarBottomConstraint: NSLayoutConstraint?
|
||||
private var patchyViewBottomConstraint: NSLayoutConstraint?
|
||||
|
||||
/**
|
||||
The actual tab bar that will contain the buttons, indicator, separator, etc.
|
||||
@@ -28,10 +27,10 @@ open class TabbyController: UIViewController, UINavigationControllerDelegate {
|
||||
tabby.delegate = self
|
||||
|
||||
return tabby
|
||||
}()
|
||||
}()
|
||||
|
||||
/// A view behind TabbyBar to patch in the bottom in case of safeArea
|
||||
private lazy var patchyView: UIView = {
|
||||
fileprivate lazy var patchyView: UIView = {
|
||||
let view = UIView()
|
||||
view.backgroundColor = Constant.Color.background
|
||||
return view
|
||||
@@ -222,7 +221,7 @@ open class TabbyController: UIViewController, UINavigationControllerDelegate {
|
||||
controller.view.translatesAutoresizingMaskIntoConstraints = false
|
||||
|
||||
addChildViewController(controller)
|
||||
view.insertSubview(controller.view, belowSubview: tabbyBar)
|
||||
view.insertSubview(controller.view, belowSubview: patchyView)
|
||||
tabbyBar.prepareTranslucency(translucent)
|
||||
applyNewConstraints(controller)
|
||||
}
|
||||
@@ -280,19 +279,20 @@ open class TabbyController: UIViewController, UINavigationControllerDelegate {
|
||||
// MARK: - Constraints
|
||||
|
||||
func setupConstraints() {
|
||||
patchyViewBottomConstraint = patchyView.bottomAnchor.constraint(
|
||||
equalTo: view.bottomAnchor
|
||||
)
|
||||
|
||||
Constraint.on(
|
||||
tabbyBar.leadingAnchor.constraint(equalTo: view.leadingAnchor),
|
||||
tabbyBar.trailingAnchor.constraint(equalTo: view.trailingAnchor),
|
||||
tabbyBar.heightAnchor.constraint(equalToConstant: Constant.Dimension.height),
|
||||
|
||||
patchyView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
|
||||
patchyView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
|
||||
patchyViewBottomConstraint!
|
||||
)
|
||||
if #available(iOS 9.0, *) {
|
||||
Constraint.on(
|
||||
tabbyBar.rightAnchor.constraint(equalTo: view.rightAnchor),
|
||||
tabbyBar.leftAnchor.constraint(equalTo: view.leftAnchor),
|
||||
tabbyBar.heightAnchor.constraint(equalToConstant: Constant.Dimension.height),
|
||||
|
||||
patchyView.topAnchor.constraint(equalTo: tabbyBar.bottomAnchor),
|
||||
patchyView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
|
||||
patchyView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
|
||||
patchyView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
|
||||
)
|
||||
} else {
|
||||
// Fallback on earlier versions
|
||||
}
|
||||
|
||||
if #available(iOS 11, *) {
|
||||
tabbyBarBottomConstraint = tabbyBar.bottomAnchor.constraint(
|
||||
@@ -300,17 +300,19 @@ open class TabbyController: UIViewController, UINavigationControllerDelegate {
|
||||
)
|
||||
|
||||
Constraint.on(
|
||||
tabbyBarBottomConstraint!,
|
||||
patchyView.heightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.heightAnchor)
|
||||
tabbyBarBottomConstraint!
|
||||
)
|
||||
} else {
|
||||
tabbyBarBottomConstraint = tabbyBar.bottomAnchor.constraint(
|
||||
equalTo: view.bottomAnchor
|
||||
)
|
||||
if #available(iOS 9.0, *) {
|
||||
tabbyBarBottomConstraint = tabbyBar.bottomAnchor.constraint(
|
||||
equalTo: view.bottomAnchor
|
||||
)
|
||||
} else {
|
||||
// Fallback on earlier versions
|
||||
}
|
||||
|
||||
Constraint.on(
|
||||
tabbyBarBottomConstraint!,
|
||||
patchyView.heightAnchor.constraint(equalToConstant: 0)
|
||||
tabbyBarBottomConstraint!
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -319,7 +321,6 @@ open class TabbyController: UIViewController, UINavigationControllerDelegate {
|
||||
|
||||
public func showTabbar() {
|
||||
tabbyBarBottomConstraint?.constant = 0
|
||||
patchyViewBottomConstraint?.constant = 0
|
||||
tabbyBar.indicator.alpha = showIndicator ? 1 : 0
|
||||
|
||||
UIView.animate(withDuration: 0.25) {
|
||||
@@ -329,7 +330,6 @@ open class TabbyController: UIViewController, UINavigationControllerDelegate {
|
||||
|
||||
public func hideTabbar() {
|
||||
tabbyBarBottomConstraint?.constant = 200
|
||||
patchyViewBottomConstraint?.constant = -200
|
||||
tabbyBar.indicator.alpha = 0
|
||||
|
||||
UIView.animate(withDuration: 0.25) {
|
||||
@@ -389,7 +389,7 @@ extension TabbyController: TabbyBarDelegate {
|
||||
controller.view.translatesAutoresizingMaskIntoConstraints = false
|
||||
|
||||
addChildViewController(controller)
|
||||
view.insertSubview(controller.view, belowSubview: tabbyBar)
|
||||
view.insertSubview(controller.view, belowSubview: patchyView)
|
||||
|
||||
applyNewConstraints(controller)
|
||||
}
|
||||
|
||||
@@ -13,9 +13,6 @@ public protocol TabbyBarDelegate: class {
|
||||
*/
|
||||
open class TabbyBar: UIView {
|
||||
|
||||
static let collectionObserver = "contentSize"
|
||||
static let KVOContext = UnsafeMutableRawPointer(mutating: nil)
|
||||
|
||||
lazy var translucentView: UIVisualEffectView = UIVisualEffectView(effect: UIBlurEffect(style: .light))
|
||||
|
||||
lazy var layout: TabbyLayout = {
|
||||
@@ -54,7 +51,6 @@ open class TabbyBar: UIView {
|
||||
var selectedItem: Int = 0 {
|
||||
didSet {
|
||||
positionIndicator(selectedItem)
|
||||
collectionView.reloadData()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,26 +71,12 @@ open class TabbyBar: UIView {
|
||||
self.items = items
|
||||
super.init(frame: .zero)
|
||||
|
||||
backgroundColor = Constant.Color.background
|
||||
|
||||
collectionView.addObserver(
|
||||
self, forKeyPath: TabbyBar.collectionObserver,
|
||||
options: .old, context: TabbyBar.KVOContext)
|
||||
backgroundColor = .clear
|
||||
|
||||
setupCollectionView()
|
||||
setupConstraints()
|
||||
}
|
||||
|
||||
open override func observeValue(
|
||||
forKeyPath keyPath: String?, of object: Any?,
|
||||
change: [NSKeyValueChangeKey : Any]?,
|
||||
context: UnsafeMutableRawPointer?) {
|
||||
guard context == TabbyBar.KVOContext else {
|
||||
return
|
||||
}
|
||||
positionIndicator(selectedItem, animate: false)
|
||||
}
|
||||
|
||||
/**
|
||||
Initializer.
|
||||
*/
|
||||
@@ -102,10 +84,6 @@ open class TabbyBar: UIView {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
deinit {
|
||||
collectionView.removeObserver(self, forKeyPath: TabbyBar.collectionObserver)
|
||||
}
|
||||
|
||||
// MARK: - Collection View setup
|
||||
|
||||
func setupCollectionView() {
|
||||
@@ -121,14 +99,21 @@ open class TabbyBar: UIView {
|
||||
// Animations
|
||||
|
||||
func positionIndicator(_ index: Int, animate: Bool = true) {
|
||||
guard let source = collectionView.dataSource , index < items.count else { return }
|
||||
guard collectionView.dataSource != nil,
|
||||
index < items.count else {
|
||||
return
|
||||
}
|
||||
|
||||
let indexPath = IndexPath(row: index, section: 0)
|
||||
guard let cell = collectionView.cellForItem(at: indexPath) else {
|
||||
return
|
||||
}
|
||||
|
||||
UIView.animate(
|
||||
withDuration: animate ? 0.7 : 0, delay: 0, usingSpringWithDamping: 0.6,
|
||||
initialSpringVelocity: 0, options: [.curveEaseIn], animations: {
|
||||
self.indicator.center.x = source.collectionView(
|
||||
self.collectionView, cellForItemAt: IndexPath(row: index, section: 0)).center.x
|
||||
}, completion: nil)
|
||||
self.indicator.center.x = cell.center.x
|
||||
}, completion: nil)
|
||||
}
|
||||
|
||||
// MARK: - Translucency
|
||||
@@ -157,31 +142,52 @@ open class TabbyBar: UIView {
|
||||
: .bottom
|
||||
constraint(indicator, attributes: .left, indicatorLayoutAttribute)
|
||||
addConstraints([
|
||||
NSLayoutConstraint(item: indicator,
|
||||
NSLayoutConstraint(
|
||||
item: indicator,
|
||||
attribute: .width, relatedBy: .equal,
|
||||
toItem: nil, attribute: .notAnAttribute,
|
||||
multiplier: 1, constant: Constant.Dimension.Indicator.width),
|
||||
|
||||
NSLayoutConstraint(item: indicator,
|
||||
NSLayoutConstraint(
|
||||
item: indicator,
|
||||
attribute: .height, relatedBy: .equal,
|
||||
toItem: nil, attribute: .notAnAttribute,
|
||||
multiplier: 1, constant: Constant.Dimension.Indicator.height)
|
||||
])
|
||||
])
|
||||
|
||||
separator.translatesAutoresizingMaskIntoConstraints = false
|
||||
addSubview(separator)
|
||||
constraint(separator, attributes: .width, .top, .right)
|
||||
addConstraint(
|
||||
NSLayoutConstraint(item: separator,
|
||||
attribute: .height, relatedBy: .equal,
|
||||
toItem: nil, attribute: .notAnAttribute,
|
||||
multiplier: 1, constant: Constant.Dimension.Separator.height)
|
||||
attribute: .height, relatedBy: .equal,
|
||||
toItem: nil, attribute: .notAnAttribute,
|
||||
multiplier: 1, constant: Constant.Dimension.Separator.height)
|
||||
)
|
||||
|
||||
collectionView.translatesAutoresizingMaskIntoConstraints = false
|
||||
addSubview(collectionView)
|
||||
constraint(collectionView, attributes: .top, .bottom, .leading, .trailing)
|
||||
}
|
||||
|
||||
// MAKR: - Selection
|
||||
|
||||
/// Handle selection on a cell
|
||||
/// This call Constant.tapItemAnimation on the found UIImageView by default.
|
||||
///
|
||||
/// - Parameter indexPath: The indexPath of the selected cell
|
||||
open func handleSelection(indexPath: IndexPath) {
|
||||
guard let cell = collectionView.cellForItem(at: indexPath) else {
|
||||
return
|
||||
}
|
||||
|
||||
guard let imageView = cell.contentView.subviews
|
||||
.flatMap({ $0 as? UIImageView }).first else {
|
||||
return
|
||||
}
|
||||
|
||||
Constant.tapItemAnimation(imageView)
|
||||
}
|
||||
}
|
||||
|
||||
extension TabbyBar: UICollectionViewDelegate {
|
||||
@@ -198,6 +204,7 @@ extension TabbyBar: UICollectionViewDelegate {
|
||||
selectedItem = position
|
||||
}
|
||||
|
||||
handleSelection(indexPath: indexPath)
|
||||
delegate?.tabbyButtonDidPress(position)
|
||||
}
|
||||
}
|
||||
@@ -209,8 +216,8 @@ extension TabbyBar: UICollectionViewDataSource {
|
||||
}
|
||||
|
||||
public func collectionView(_ collectionView: UICollectionView,
|
||||
cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
||||
|
||||
cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
||||
|
||||
guard let cell = collectionView.dequeueReusableCell(
|
||||
withReuseIdentifier: Constant.cellType.reusableIdentifier, for: indexPath)
|
||||
as? TabbyCell else { return UICollectionViewCell() }
|
||||
|
||||
@@ -359,7 +359,7 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.2;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
@@ -410,7 +410,7 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.2;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 188 KiB |
Reference in New Issue
Block a user