Instantly share code, notes, and snippets.
Created
November 11, 2018 18:14
-
Star
(0)
0
You must be signed in to star a gist -
Fork
(0)
0
You must be signed in to fork a gist
-
Save glennposadas/43b609ecf8d6c088137da47bccd8b761 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// ViewController.swift | |
// TestNavigation | |
// | |
// Created by Glenn Von C. Posadas on 11/11/2018. | |
// Copyright © 2018 Glenn Von C. Posadas. All rights reserved. | |
// | |
import UIKit | |
class BaseViewController: UIViewController { | |
private var hasCustomBackButton: Bool = false | |
/// Edged chevron for iOS 10. | |
/// Curved chevron for iOS 11 and above. | |
private lazy var button_Back: UIButton = { | |
let button = UIButton(type: .custom) | |
let image = ProcessInfo.processInfo.operatingSystemVersion.majorVersion < 11 ? | |
UIImage(named: "ic_chevron_back_edged") : UIImage(named: "ic_chevron_back") | |
var imageInsets: UIEdgeInsets! | |
let iOSVersion = ProcessInfo.processInfo.operatingSystemVersion.majorVersion | |
switch iOSVersion { | |
case 11: | |
imageInsets = UIEdgeInsets(top: 0, left: -8, bottom: 0, right: 0) | |
default: | |
imageInsets = UIEdgeInsets(top: 0, left: -16, bottom: 0, right: 0) | |
} | |
button.setImage(image, for: .normal) | |
button.imageEdgeInsets = imageInsets | |
button.addTarget(self, action: #selector(self.popVC), for: .touchUpInside) | |
return button | |
}() | |
func addBackButton() { | |
if self.navigationController?.viewControllers.first == self { | |
self.hasCustomBackButton = false | |
return | |
} | |
self.hasCustomBackButton = true | |
let backBarButton = UIBarButtonItem(customView: self.button_Back) | |
self.button_Back.frame = CGRect(x: 0, y: 0, width: 44.0, height: 44.0) | |
self.navigationItem.leftBarButtonItem = backBarButton | |
self.navigationController?.interactivePopGestureRecognizer?.delegate = self | |
} | |
override func viewDidLoad() { | |
super.viewDidLoad() | |
} | |
override func viewDidLayoutSubviews() { | |
super.viewDidLayoutSubviews() | |
if self.hasCustomBackButton { | |
self.navigationController?.fixNavigationItemsMargin(0) | |
} | |
} | |
override func viewDidAppear(_ animated: Bool) { | |
super.viewDidAppear(animated) | |
if self.hasCustomBackButton { | |
self.navigationController?.fixNavigationItemsMargin(0) | |
} | |
} | |
@objc private func popVC() { | |
if let navCon = self.navigationController { | |
navCon.popViewController(animated: true) | |
} | |
} | |
} | |
extension BaseViewController: UIGestureRecognizerDelegate { | |
} | |
////=-=-=-=-=-=-=-= | |
class ViewController: BaseViewController { | |
override func viewDidLoad() { | |
super.viewDidLoad() | |
self.view.backgroundColor = .white | |
} | |
override func viewWillAppear(_ animated: Bool) { | |
super.viewWillAppear(animated) | |
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(3)) { | |
self.navigationItem.title = "" | |
self.navigationController?.pushViewController(VC2(), animated: true) | |
} | |
} | |
} | |
class VC3: BaseViewController { | |
override func viewDidLoad() { | |
super.viewDidLoad() | |
self.view.backgroundColor = .green | |
self.addBackButton() | |
} | |
} | |
class VC2: BaseViewController { | |
override func viewDidLoad() { | |
super.viewDidLoad() | |
self.view.backgroundColor = .lightGray | |
} | |
override func viewWillAppear(_ animated: Bool) { | |
super.viewWillAppear(animated) | |
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(3)) { | |
self.navigationItem.title = "" | |
self.navigationController?.pushViewController(VC3(), animated: true) | |
} | |
} | |
// override func viewDidLayoutSubviews() { | |
// super.viewDidLayoutSubviews() | |
// navigationController?.fixNavigationItemsMargin(40) | |
// } | |
// override func viewDidAppear(_ animated: Bool) { | |
// super.viewDidAppear(animated) | |
// navigationController?.fixNavigationItemsMargin(40) | |
// } | |
} | |
// do common initilizer | |
class BaseNavigationController: UINavigationController { | |
override func viewDidLayoutSubviews() { | |
super.viewDidLayoutSubviews() | |
fixNavigationItemsMargin() | |
} | |
override func viewDidAppear(_ animated: Bool) { | |
super.viewDidAppear(animated) | |
fixNavigationItemsMargin() | |
} | |
} | |
extension UINavigationController { | |
func fixNavigationItemsMargin(_ margin: CGFloat = 0) { | |
let systemMajorVersion = ProcessInfo.processInfo.operatingSystemVersion.majorVersion | |
if systemMajorVersion >= 11 { | |
// iOS >= 11 | |
guard let contentView = navigationBar.subviews | |
.first( | |
where: { sub in | |
String(describing: sub).contains("ContentView") | |
}) else { return } | |
// refer to: https://www.matrixprojects.net/p/uibarbuttonitem-ios11/ | |
// if rightBarButtonItems has not any custom views, then margin would be 8(320|375)/12(414) | |
// should use customView | |
let needAdjustRightItems: Bool | |
if let currentVC = viewControllers.last, | |
let rightItems = currentVC.navigationItem.rightBarButtonItems, | |
rightItems.count > 0, | |
rightItems.filter({ $0.customView != nil }).count > 0 { | |
needAdjustRightItems = true | |
} else { | |
print("Use 8(320|375)/12(414), if need precious margin ,use UIBarButtonItem(customView:)!!!") | |
needAdjustRightItems = false | |
} | |
let needAdjustLeftItems: Bool | |
if let currentVC = viewControllers.last, | |
let leftItems = currentVC.navigationItem.leftBarButtonItems, | |
leftItems.count > 0, | |
leftItems.filter({ $0.customView != nil }).count > 0 { | |
needAdjustLeftItems = true | |
} else { | |
print("Use 8(320|375)/12(414), if need precious margin ,use UIBarButtonItem(customView:)!!!") | |
needAdjustLeftItems = false | |
} | |
let layoutMargins: UIEdgeInsets | |
if #available(iOS 11.0, *) { | |
let directionInsets = contentView.directionalLayoutMargins | |
layoutMargins = UIEdgeInsets( | |
top: directionInsets.top, | |
left: directionInsets.leading, | |
bottom: directionInsets.bottom, | |
right: directionInsets.trailing) | |
} else { | |
layoutMargins = contentView.layoutMargins | |
} | |
contentView.constraints.forEach( | |
{ cst in | |
// iOS 11 the distance between rightest item and NavigationBar should be margin | |
// rightStackView trailing space is -margin / 2 | |
// rightestItem trailing to rightStackView trailing is -margin / 2 | |
let rightConstant = -margin / 2 | |
switch (cst.firstAttribute, cst.secondAttribute) { | |
case (.leading, .leading), (.trailing, .trailing): | |
if let stackView = cst.firstItem as? UIStackView, | |
stackView.frame.minX < navigationBar.frame.midX { | |
// is leftItems | |
if needAdjustLeftItems { | |
cst.constant = margin - layoutMargins.left | |
} | |
} else if let layoutGuide = cst.firstItem as? UILayoutGuide, | |
layoutGuide.layoutFrame.minX < navigationBar.frame.midX { | |
// is leftItems | |
if needAdjustLeftItems { | |
cst.constant = margin - layoutMargins.left | |
} | |
} | |
if let stackView = cst.firstItem as? UIStackView, | |
stackView.frame.maxX > navigationBar.frame.midX { | |
// is rightItems | |
if needAdjustRightItems { | |
cst.constant = rightConstant | |
} | |
} else if let layoutGuide = cst.firstItem as? UILayoutGuide, | |
layoutGuide.layoutFrame.maxX > navigationBar.frame.midX { | |
// is rightItems | |
if needAdjustRightItems { | |
cst.constant = rightConstant | |
} | |
} | |
default: break | |
} | |
}) | |
// ensure items space == 8, minispcae | |
contentView.subviews.forEach( | |
{ subsub in | |
guard subsub is UIStackView else { return } | |
subsub.constraints.forEach( | |
{ cst in | |
guard cst.firstAttribute == .width | |
|| cst.secondAttribute == .width | |
else { return } | |
cst.constant = 0 | |
}) | |
}) | |
} else { | |
// iOS < 11 | |
let versionItemsCount: Int | |
if systemMajorVersion == 10 { | |
// iOS 10 navigationItem.rightBarButtonItems == 0 | |
// space = 16(320|375) / 20(414) | |
// should adjust margin | |
versionItemsCount = 0 | |
} else { | |
// iOS 9 navigationItem.rightBarButtonItems == 0 | |
// space = 8(320|375) / 12(414) | |
// should not adjust margin | |
versionItemsCount = 1 | |
} | |
let spaceProducer = { () -> UIBarButtonItem in | |
let spaceItem = UIBarButtonItem( | |
barButtonSystemItem: .fixedSpace, | |
target: nil, | |
action: nil) | |
spaceItem.width = margin - 16 | |
return spaceItem | |
} | |
if let currentVC = viewControllers.last, | |
var rightItems = currentVC.navigationItem.rightBarButtonItems, | |
rightItems.count > versionItemsCount, | |
let first = rightItems.first { | |
// ensure the first BarButtonItem is NOT fixedSpace | |
if first.title == nil && first.image == nil && first.customView == nil { | |
print("rightBarButtonItems SPACE SETTED!!! SPACE: ", abs(first.width)) | |
} else { | |
rightItems.insert(spaceProducer(), at: 0) | |
// arranged right -> left | |
currentVC.navigationItem.rightBarButtonItems = rightItems | |
} | |
} | |
if let currentVC = viewControllers.last, | |
var leftItems = currentVC.navigationItem.leftBarButtonItems, | |
leftItems.count > versionItemsCount, | |
let first = leftItems.first { | |
if first.title == nil && first.image == nil && first.customView == nil { | |
print("leftBarButtonItems SPACE SETTED!!! SPACE: ", abs(first.width)) | |
} else { | |
leftItems.insert(spaceProducer(), at: 0) | |
// arranged left -> right | |
currentVC.navigationItem.leftBarButtonItems = leftItems | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment