Commit 15d33bde by Daniel Dahan

updated NavigationController and NavigationBar to utilize the Toolbar and remove duplicate code

parent 68e44743
...@@ -108,7 +108,7 @@ open class Bar: View { ...@@ -108,7 +108,7 @@ open class Bar: View {
open let contentView = UIView() open let contentView = UIView()
/// Left side UIViews. /// Left side UIViews.
open var leftViews: [UIView] { open var leftViews = [UIView]() {
didSet { didSet {
for v in oldValue { for v in oldValue {
v.removeFromSuperview() v.removeFromSuperview()
...@@ -118,7 +118,7 @@ open class Bar: View { ...@@ -118,7 +118,7 @@ open class Bar: View {
} }
/// Right side UIViews. /// Right side UIViews.
open var rightViews: [UIView] { open var rightViews = [UIView]() {
didSet { didSet {
for v in oldValue { for v in oldValue {
v.removeFromSuperview() v.removeFromSuperview()
...@@ -142,8 +142,6 @@ open class Bar: View { ...@@ -142,8 +142,6 @@ open class Bar: View {
- Parameter aDecoder: A NSCoder instance. - Parameter aDecoder: A NSCoder instance.
*/ */
public required init?(coder aDecoder: NSCoder) { public required init?(coder aDecoder: NSCoder) {
leftViews = []
rightViews = []
super.init(coder: aDecoder) super.init(coder: aDecoder)
} }
...@@ -154,8 +152,6 @@ open class Bar: View { ...@@ -154,8 +152,6 @@ open class Bar: View {
- Parameter frame: A CGRect instance. - Parameter frame: A CGRect instance.
*/ */
public override init(frame: CGRect) { public override init(frame: CGRect) {
leftViews = []
rightViews = []
super.init(frame: frame) super.init(frame: frame)
} }
......
...@@ -39,45 +39,36 @@ open class NavigationBar: UINavigationBar { ...@@ -39,45 +39,36 @@ open class NavigationBar: UINavigationBar {
open override var intrinsicContentSize: CGSize { open override var intrinsicContentSize: CGSize {
return CGSize(width: bounds.width, height: bounds.height) return CGSize(width: bounds.width, height: bounds.height)
} }
/// A preset wrapper around contentEdgeInsets. /// A preset wrapper around contentEdgeInsets.
open var contentEdgeInsetsPreset = EdgeInsetsPreset.none { open var contentEdgeInsetsPreset = EdgeInsetsPreset.none {
didSet { didSet {
contentEdgeInsets = EdgeInsetsPresetToValue(preset: contentEdgeInsetsPreset) contentEdgeInsets = EdgeInsetsPresetToValue(preset: contentEdgeInsetsPreset)
} }
} }
/// A reference to EdgeInsets. /// A reference to EdgeInsets.
@IBInspectable @IBInspectable
open var contentEdgeInsets = EdgeInsets.zero { open var contentEdgeInsets = EdgeInsets.zero {
didSet { didSet {
layoutSubviews() layoutSubviews()
} }
} }
/// A preset wrapper around interimSpace. /// A preset wrapper around interimSpace.
open var interimSpacePreset = InterimSpacePreset.none { open var interimSpacePreset = InterimSpacePreset.interimSpace3 {
didSet { didSet {
interimSpace = InterimSpacePresetToValue(preset: interimSpacePreset) interimSpace = InterimSpacePresetToValue(preset: interimSpacePreset)
} }
} }
/// A wrapper around grid.interimSpace. /// A wrapper around grid.interimSpace.
@IBInspectable @IBInspectable
open var interimSpace: InterimSpace = 0 { open var interimSpace: InterimSpace = 0 {
didSet { didSet {
layoutSubviews() layoutSubviews()
} }
} }
/// Grid cell factor.
@IBInspectable
open var gridFactor: CGFloat = 12 {
didSet {
assert(0 < gridFactor, "[Material Error: gridFactor must be greater than 0.]")
layoutSubviews()
}
}
/** /**
The back button image writes to the backIndicatorImage property and The back button image writes to the backIndicatorImage property and
...@@ -151,136 +142,6 @@ open class NavigationBar: UINavigationBar { ...@@ -151,136 +142,6 @@ open class NavigationBar: UINavigationBar {
layoutDivider() layoutDivider()
} }
open override func pushItem(_ item: UINavigationItem, animated: Bool) {
super.pushItem(item, animated: animated)
layoutNavigationItem(item: item)
}
/**
Lays out the UINavigationItem.
- Parameter item: A UINavigationItem to layout.
*/
internal func layoutNavigationItem(item: UINavigationItem) {
guard willLayout else {
return
}
prepareItem(item: item)
prepareTitleView(item: item)
item.titleView!.frame.origin = .zero
item.titleView!.frame.size = intrinsicContentSize
var lc = 0
var rc = 0
item.titleView!.grid.begin()
item.titleView!.grid.views.removeAll()
for v in item.leftViews {
if let b = v as? UIButton {
b.contentEdgeInsets = .zero
b.titleEdgeInsets = .zero
}
v.frame.size.width = v.intrinsicContentSize.width
v.sizeToFit()
v.grid.columns = Int(ceil(v.bounds.width / gridFactor)) + 2
lc += v.grid.columns
item.titleView!.grid.views.append(v)
}
item.titleView!.grid.views.append(item.contentView)
for v in item.rightViews {
if let b = v as? UIButton {
b.contentEdgeInsets = .zero
b.titleEdgeInsets = .zero
}
v.frame.size.width = v.intrinsicContentSize.width
v.sizeToFit()
v.grid.columns = Int(ceil(v.bounds.width / gridFactor)) + 2
rc += v.grid.columns
item.titleView!.grid.views.append(v)
}
item.contentView.grid.begin()
item.contentView.grid.offset.columns = 0
var l: CGFloat = 0
var r: CGFloat = 0
if .center == item.contentViewAlignment {
if item.leftViews.count < item.rightViews.count {
r = CGFloat(item.rightViews.count) * interimSpace
l = r
} else {
l = CGFloat(item.leftViews.count) * interimSpace
r = l
}
}
let p = bounds.width - l - r - contentEdgeInsets.left - contentEdgeInsets.right
let columns = Int(ceil(p / gridFactor))
if .center == item.contentViewAlignment {
if lc < rc {
item.contentView.grid.columns = columns - 2 * rc
item.contentView.grid.offset.columns = rc - lc
} else {
item.contentView.grid.columns = columns - 2 * lc
item.rightViews.first?.grid.offset.columns = lc - rc
}
} else {
item.contentView.grid.columns = columns - lc - rc
}
item.titleView!.grid.axis.columns = columns
item.titleView!.grid.interimSpace = interimSpace
item.titleView!.grid.contentEdgeInsets = contentEdgeInsets
item.titleView!.grid.commit()
item.contentView.grid.commit()
// contentView alignment.
if nil != item.title && "" != item.title {
if nil == item.titleLabel.superview {
item.contentView.addSubview(item.titleLabel)
}
item.titleLabel.frame = item.contentView.bounds
} else {
item.titleLabel.removeFromSuperview()
}
if 0 < item.detailLabel.text?.utf16.count ?? 0 {
if nil == item.detailLabel.superview {
item.contentView.addSubview(item.detailLabel)
}
if nil == item.titleLabel.superview {
item.detailLabel.frame = item.contentView.bounds
} else {
item.titleLabel.sizeToFit()
item.detailLabel.sizeToFit()
let diff = (item.contentView.bounds.height - item.titleLabel.bounds.height - item.detailLabel.bounds.height) / 2
item.titleLabel.frame.size.height += diff
item.titleLabel.frame.size.width = item.contentView.bounds.width
item.detailLabel.frame.size.height += diff
item.detailLabel.frame.size.width = item.contentView.bounds.width
item.detailLabel.frame.origin.y = item.titleLabel.bounds.height
}
} else {
item.detailLabel.removeFromSuperview()
}
}
/** /**
Prepares the view instance when intialized. When subclassing, Prepares the view instance when intialized. When subclassing,
it is recommended to override the prepare method it is recommended to override the prepare method
...@@ -292,34 +153,37 @@ open class NavigationBar: UINavigationBar { ...@@ -292,34 +153,37 @@ open class NavigationBar: UINavigationBar {
barStyle = .black barStyle = .black
isTranslucent = false isTranslucent = false
depthPreset = .depth1 depthPreset = .depth1
interimSpacePreset = .interimSpace3
contentEdgeInsetsPreset = .square1
contentScaleFactor = Screen.scale contentScaleFactor = Screen.scale
backButtonImage = Icon.cm.arrowBack backButtonImage = Icon.cm.arrowBack
contentEdgeInsetsPreset = .square1
interimSpacePreset = .interimSpace3
let image = UIImage() let image = UIImage()
shadowImage = image shadowImage = image
setBackgroundImage(image, for: .default) setBackgroundImage(image, for: .default)
backgroundColor = .white backgroundColor = .white
} }
}
/**
Prepare the item by setting the title property to equal an empty string. internal extension NavigationBar {
- Parameter item: A UINavigationItem to layout. /**
*/ Lays out the UINavigationItem.
private func prepareItem(item: UINavigationItem) {
item.hidesBackButton = false
item.setHidesBackButton(true, animated: false)
}
/**
Prepare the titleView.
- Parameter item: A UINavigationItem to layout. - Parameter item: A UINavigationItem to layout.
*/ */
private func prepareTitleView(item: UINavigationItem) { func layoutNavigationItem(item: UINavigationItem) {
guard nil == item.titleView else { guard willLayout else {
return return
} }
item.titleView = UIView(frame: .zero)
} item.titleView = item.toolbar
guard let v = item.titleView as? Toolbar else {
return
}
removeConstraints(constraints)
v.contentEdgeInsets = contentEdgeInsets
v.interimSpace = interimSpace
v.frame = bounds
}
} }
...@@ -119,18 +119,18 @@ open class NavigationController: UINavigationController { ...@@ -119,18 +119,18 @@ open class NavigationController: UINavigationController {
when subclassing. when subclassing.
*/ */
open func prepare() { open func prepare() {
isMotionEnabled = true
navigationBar.heightPreset = .normal navigationBar.heightPreset = .normal
navigationBar.frame.size.width = view.bounds.width
view.clipsToBounds = true view.clipsToBounds = true
view.backgroundColor = .white view.backgroundColor = .white
view.contentScaleFactor = Screen.scale view.contentScaleFactor = Screen.scale
// This ensures the panning gesture is available when going back between views. // This ensures the panning gesture is available when going back between views.
if let v = interactivePopGestureRecognizer { if let v = interactivePopGestureRecognizer {
v.isEnabled = true v.isEnabled = true
v.delegate = self v.delegate = self
} }
} }
/// Calls the layout functions for the view heirarchy. /// Calls the layout functions for the view heirarchy.
...@@ -156,20 +156,24 @@ extension NavigationController: UINavigationBarDelegate { ...@@ -156,20 +156,24 @@ extension NavigationController: UINavigationBarDelegate {
item.backButton.image = v.backButtonImage item.backButton.image = v.backButtonImage
} }
item.backButton.addTarget(self, action: #selector(handleBackButton), for: .touchUpInside) item.backButton.addTarget(self, action: #selector(handle(backButton:)), for: .touchUpInside)
if !item.backButton.isHidden { if !item.backButton.isHidden {
item.leftViews.insert(item.backButton, at: 0) item.leftViews.insert(item.backButton, at: 0)
} }
item.hidesBackButton = false
item.setHidesBackButton(true, animated: false)
v.layoutNavigationItem(item: item) v.layoutNavigationItem(item: item)
} }
return true return true
} }
/// Handler for the back button. /// Handler for the backbutton.
@objc @objc
internal func handleBackButton() { internal func handle(backButton: UIButton) {
popViewController(animated: true) popViewController(animated: true)
} }
} }
......
...@@ -35,59 +35,16 @@ fileprivate var NavigationItemKey: UInt8 = 0 ...@@ -35,59 +35,16 @@ fileprivate var NavigationItemKey: UInt8 = 0
fileprivate var NavigationItemContext: UInt8 = 0 fileprivate var NavigationItemContext: UInt8 = 0
fileprivate class NavigationItem: NSObject { fileprivate class NavigationItem: NSObject {
/// Should center the contentView. /// A reference to the toolbar.
var contentViewAlignment = ContentViewAlignment.center { @objc
didSet { let toolbar = Toolbar()
navigationBar?.layoutSubviews()
}
}
/// Back Button. /// Back Button.
lazy var backButton = IconButton() lazy var backButton = IconButton()
/// Content View.
var contentView = UIView()
/// Title label.
@objc
var titleLabel = UILabel()
/// Detail label.
var detailLabel = UILabel()
/// Left items.
var leftViews = [UIView]() {
didSet {
for v in oldValue {
v.removeFromSuperview()
}
navigationBar?.layoutSubviews()
}
}
/// Right items.
var rightViews = [UIView]() {
didSet {
for v in oldValue {
v.removeFromSuperview()
}
navigationBar?.layoutSubviews()
}
}
/// Center items.
var centerViews: [UIView] {
get {
return contentView.grid.views
}
set(value) {
contentView.grid.views = value
}
}
/// An optional reference to the NavigationBar. /// An optional reference to the NavigationBar.
var navigationBar: NavigationBar? { var navigationBar: NavigationBar? {
var v = contentView.superview var v = toolbar.contentView.superview
while nil != v { while nil != v {
if let navigationBar = v as? NavigationBar { if let navigationBar = v as? NavigationBar {
return navigationBar return navigationBar
...@@ -96,76 +53,43 @@ fileprivate class NavigationItem: NSObject { ...@@ -96,76 +53,43 @@ fileprivate class NavigationItem: NSObject {
} }
return nil return nil
} }
}
open override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
guard "titleLabel.textAlignment" == keyPath else { fileprivate extension UINavigationItem {
super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context) /// NavigationItem reference.
return var navigationItem: NavigationItem {
get {
return AssociatedObject.get(base: self, key: &NavigationItemKey) {
return NavigationItem()
}
}
set(value) {
AssociatedObject.set(base: self, key: &NavigationItemKey, value: value)
} }
contentViewAlignment = .center == titleLabel.textAlignment ? .center : .full
}
deinit {
removeObserver(self, forKeyPath: #keyPath(titleLabel.textAlignment))
} }
}
/// Initializer.
override init() { internal extension UINavigationItem {
super.init() /// A reference to the NavigationItem Toolbar.
prepareTitleLabel() var toolbar: Toolbar {
prepareDetailLabel() return navigationItem.toolbar
}
/// Reloads the subviews for the NavigationBar.
func reload() {
navigationBar?.layoutSubviews()
} }
/// Prepares the titleLabel.
func prepareTitleLabel() {
titleLabel.textAlignment = .center
titleLabel.contentScaleFactor = Screen.scale
titleLabel.font = RobotoFont.medium(with: 17)
titleLabel.textColor = Color.darkText.primary
addObserver(self, forKeyPath: #keyPath(titleLabel.textAlignment), options: [], context: &NavigationItemContext)
}
/// Prepares the detailLabel.
func prepareDetailLabel() {
detailLabel.textAlignment = .center
titleLabel.contentScaleFactor = Screen.scale
detailLabel.font = RobotoFont.regular(with: 12)
detailLabel.textColor = Color.darkText.secondary
}
} }
extension UINavigationItem { extension UINavigationItem {
/// NavigationItem reference. /// Should center the contentView.
fileprivate var navigationItem: NavigationItem {
get {
return AssociatedObject.get(base: self, key: &NavigationItemKey) {
return NavigationItem()
}
}
set(value) {
AssociatedObject.set(base: self, key: &NavigationItemKey, value: value)
}
}
/// Should center the contentView.
open var contentViewAlignment: ContentViewAlignment { open var contentViewAlignment: ContentViewAlignment {
get { get {
return navigationItem.contentViewAlignment return toolbar.contentViewAlignment
} }
set(value) { set(value) {
navigationItem.contentViewAlignment = value toolbar.contentViewAlignment = value
} }
} }
/// Content View. /// Content View.
open var contentView: UIView { open var contentView: UIView {
return navigationItem.contentView return toolbar.contentView
} }
/// Back Button. /// Back Button.
...@@ -175,41 +99,41 @@ extension UINavigationItem { ...@@ -175,41 +99,41 @@ extension UINavigationItem {
/// Title Label. /// Title Label.
open var titleLabel: UILabel { open var titleLabel: UILabel {
return navigationItem.titleLabel return toolbar.titleLabel
} }
/// Detail Label. /// Detail Label.
open var detailLabel: UILabel { open var detailLabel: UILabel {
return navigationItem.detailLabel return toolbar.detailLabel
} }
/// Left side UIViews. /// Left side UIViews.
open var leftViews: [UIView] { open var leftViews: [UIView] {
get { get {
return navigationItem.leftViews return toolbar.leftViews
} }
set(value) { set(value) {
navigationItem.leftViews = value toolbar.leftViews = value
} }
} }
/// Right side UIViews. /// Right side UIViews.
open var rightViews: [UIView] { open var rightViews: [UIView] {
get { get {
return navigationItem.rightViews return toolbar.rightViews
} }
set(value) { set(value) {
navigationItem.rightViews = value toolbar.rightViews = value
} }
} }
/// Center UIViews. /// Center UIViews.
open var centerViews: [UIView] { open var centerViews: [UIView] {
get { get {
return navigationItem.centerViews return toolbar.centerViews
} }
set(value) { set(value) {
navigationItem.centerViews = value toolbar.centerViews = value
} }
} }
} }
...@@ -68,6 +68,7 @@ open class Toolbar: Bar { ...@@ -68,6 +68,7 @@ open class Toolbar: Bar {
super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context) super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
return return
} }
contentViewAlignment = .center == titleLabel.textAlignment ? .center : .full contentViewAlignment = .center == titleLabel.textAlignment ? .center : .full
} }
......
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