我正在尝试将相同的导航栏项添加到我的应用程序中的每个选项卡。我目前在homeController中正确设置它们,但我想将代码移动到一个单独的文件中,并在任何我想要的地方远程实现它。
例如:在导航栏的左侧添加[搜索]图标,而不必在每个swift文件中使用相同的代码。
我不知道是否应该创建枚举,协议或类。这样做的最佳方式是什么?
let menuButton = UIButton(type: UIButtonType.system)
menuButton.frame = CGRect(x: 0, y: 0, width: 20, height: 20)
menuButton.addTarget(self, action: #selector(openSearch), for: .touchUpInside)
menuButton.setImage(UIImage(named: "icon_search"), for: UIControlState())
let menuBarButtonItem = UIBarButtonItem(customView: menuButton)
navigationItem.leftBarButtonItems = [menuBarButtonItem]
func openSearch() {
// Some code
}
答案 0 :(得分:10)
我建议的方法是创建一个基本视图控制器类,并使所有单独的视图控制器从此而不是直接从UIViewController
开始。
虽然您可以像Umair建议的那样进行快速而又脏的扩展,但这对其他应用程序来说并不实用,而基本视图控制器允许您基本上添加功能/自定义应用程序中所有视图控制器的任何方面的外观
以下是一些示例代码:
class BaseViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let menuButton = UIButton(type: UIButtonType.system)
menuButton.frame = CGRect(x: 0, y: 0, width: 20, height: 20)
menuButton.addTarget(self, action: #selector(openSearch), for: .touchUpInside)
menuButton.setImage(UIImage(named: "icon_search"), for: UIControlState())
let menuBarButtonItem = UIBarButtonItem(customView: menuButton)
navigationItem.leftBarButtonItems = [menuBarButtonItem
}
func openSearch() {
}
}
然后,对于您应用中的所有视图控制器,只需进行声明:
class SomeRandomViewController: BaseViewController { }
修改强>
正如评论中正确指出的那样,您必须在每个 base 类中执行此操作。 (UIViewController,UITableViewController,UITabViewController等...)有一种方法,但它通常被认为是Objective-C运行时的黑暗艺术之一。我当然是在谈论方法调整。以下代码基本上交换了UIViewController
' viewWillAppear:
的实现和自定义方法。如果正确完成,这是完全安全的,下面显示了正确的实现。
extension UIViewController {
public override class func initialize() {
struct Static {
static var token: dispatch_once_t = 0
}
// make sure this isn't a subclass
if self !== UIViewController.self {
return
}
dispatch_once(&Static.token) {
let originalSelector = Selector("viewWillAppear:")
let swizzledSelector = Selector("extended_viewWillAppear:")
let originalMethod = class_getInstanceMethod(self, originalSelector)
let swizzledMethod = class_getInstanceMethod(self, swizzledSelector)
let didAddMethod = class_addMethod(self, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))
if didAddMethod {
class_replaceMethod(self, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod))
} else {
method_exchangeImplementations(originalMethod, swizzledMethod)
}
}
}
// MARK: - Method Swizzling
func extended_viewWillAppear(animated: Bool) {
self.extended_viewWillAppear(animated)
// Call your code here that you want to run for all view controllers, table view controllers, tab view controllers etc...
}
}
有些开发人员无法忍受上述概念,您应该意识到它可能会在未来的iOS版本中发生变化并中断。也就是说,它不会让你的应用被拒绝,因为它是一种实际的编程技术。
答案 1 :(得分:0)
您可以通过扩展UIViewController来轻松使用它
扩展UIViewController {
func setupRemainingNavItems() {
self.navigationController?.setNavigationBarHidden(false, animated: true)
navigationController?.navigationBar.setBackgroundImage(UIImage(), for: UIBarMetrics.default)
navigationController?.navigationBar.shadowImage = UIImage()
let titleImageView = UIImageView(image: #imageLiteral(resourceName: "trukk-icon"))
titleImageView.frame = CGRect(x: 0, y: 0, width: 30, height: 30)
titleImageView.contentMode = .scaleAspectFit
titleImageView.clipsToBounds = true
navigationItem.titleView = titleImageView
let button = UIButton(type: .custom)
button.setImage(UIImage (named: "Group 6"), for: .normal)
button.frame = CGRect(x: 0.0, y: 0.0, width: 30.0, height: 30.0)
button.addTarget(self, action: #selector(tapbutton), for: .touchUpInside)
let barButtonItem = UIBarButtonItem(customView: button)
self.navigationItem.leftBarButtonItem = barButtonItem
}
@objc func tapbutton(){
self.navigationController?.popViewController(animated: true)
print("tap")
}
}
用途:
在ViewDidLoad()中调用它
setupRemainingNavItems()
答案 2 :(得分:0)
面向未来的人
如果不是subclassing
和hardcoding buttons
的话,这就是我的解决方法:
navigation bar
中的Storyboard
中添加所需的按钮outlets/actions
连接到您的TabBarController
TabBarController --> NavigationController --> tab1/tab2/tab3
的{{1}}中的viewDidLoad()
,请添加:TabBarController