ios - Swift - 将相同的导航栏项目添加到每个页面

标签 ios swift

我正在尝试将相同的导航栏项目添加到我的应用程序中的每个选项卡。我目前在我的 homeController 中正确设置了它们,但我想将代码移动到一个单独的文件并在我想要的任何地方远程实现它。

例如:在导航栏左侧添加一个[搜索]图标,而不必在每个swift文件中使用相同的代码。

我不知道我是否应该创建枚举、协议(protocol)或类。执行此操作的最佳方法是什么?

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
}

最佳答案

我推荐的方法是创建一个基本 View Controller 类,并使所有单独的 View Controller 继承自该类,而不是直接继承自 UIViewController

虽然您可以按照 Umair 的建议进行快速而肮脏的扩展,但这对于其他应用程序并不实用,而基本 View Controller 允许您基本上添加功能/自定义应用程序中所有 View Controller 的任何方面的外观。

下面是一些示例代码:

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() {

    }
}

然后对于您应用中的所有 View Controller ,只需声明:

class SomeRandomViewController: BaseViewController { }

编辑:

正如评论中正确指出的那样,您必须在每个基础 类中执行此操作。 (UIViewController、UITableViewController、UITabViewController 等...)有一种解决方法,但它通常被认为是 Objective-C 运行时的黑暗艺术之一。我当然是在谈论方法调配。以下代码实质上交换了 UIViewControllerviewWillAppear: 和自定义方法的实现。如果操作正确,它是完全安全的,正确的实现如下所示。

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 版本中发生变化并中断。也就是说,它不会让您的应用程序被拒绝,因为它是一种实际的编程技术。

关于ios - Swift - 将相同的导航栏项目添加到每个页面,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40780919/

相关文章:

ios - 记住 tableView 中选定的单元格

ios - 在 SceneKit 中绘制平面

ios - 如何更改 iOS 11 中的导航栏高度?

swift - 检查结构中的任何属性是否为 nil - Swift 4

快速测量等级·角度转换精度

ios - 从 Collection View 数组 Swift 中删除 Collection View 单元格

ios - 如何在 xCode 5 上安装 iOS 4.3 模拟器?

ios - 使用 Firebase 电话身份验证未收到通知

ios - Cocoapods 中的嵌入式二进制文件?

objective-c - 如何确定当前日期是否在不包含年份的两个日期范围之内/之外?