关于UINavigationBar
有一个小问题,我在努力克服它。当您使用视图控制器中的prefersStatusBarHidden()
方法隐藏状态栏时(我不想禁用整个应用程序的状态栏),导航栏将失去属于状态栏的20pt高度,即导航栏会缩小。
我试过不同的解决方法,但发现每种方法都有缺点。然后我找到了这个类别,它使用方法交换,在UINavigationBar
类中添加了一个名为fixedHeightWhenStatusBarHidden
的属性,可以解决此问题。我在Objective-C中测试过,它可以工作。以下是原始Objective-C代码的头文件和实现文件。
现在,由于我正在使用Swift编写我的应用程序,所以我尝试将其翻译为Swift。
我面临的第一个问题是,Swift扩展无法有存储属性。因此,我不得不使用计算属性来声明fixedHeightWhenStatusBarHidden
属性,从而使我能够设置值。但这引发了另一个问题。显然,您不能为计算属性分配值。就像这样。
self.navigationController?.navigationBar.fixedHeightWhenStatusBarHidden = true
我遇到了错误无法对此表达式的结果进行赋值。
以下是我的代码。它可以编译通过,但是它不起作用。
import Foundation
import UIKit
extension UINavigationBar {
var fixedHeightWhenStatusBarHidden: Bool {
return objc_getAssociatedObject(self, "FixedNavigationBarSize").boolValue
}
func sizeThatFits_FixedHeightWhenStatusBarHidden(size: CGSize) -> CGSize {
if UIApplication.sharedApplication().statusBarHidden && fixedHeightWhenStatusBarHidden {
let newSize = CGSizeMake(self.frame.size.width, 64)
return newSize
} else {
return sizeThatFits_FixedHeightWhenStatusBarHidden(size)
}
}
/*
func fixedHeightWhenStatusBarHidden() -> Bool {
return objc_getAssociatedObject(self, "FixedNavigationBarSize").boolValue
}
*/
func setFixedHeightWhenStatusBarHidden(fixedHeightWhenStatusBarHidden: Bool) {
objc_setAssociatedObject(self, "FixedNavigationBarSize", NSNumber(bool: fixedHeightWhenStatusBarHidden), UInt(OBJC_ASSOCIATION_RETAIN))
}
override public class func load() {
method_exchangeImplementations(class_getInstanceMethod(self, "sizeThatFits:"), class_getInstanceMethod(self, "sizeThatFits_FixedHeightWhenStatusBarHidden:"))
}
}
由于保留此方法会导致方法重新声明错误,因此代码中间的fixedHeightWhenStatusBarHidden()
方法已被注释掉。
我之前没有在Swift或Objective-C中进行过方法交换,所以我不确定解决这个问题的下一步是什么,甚至是否可能解决。
有人可以帮忙吗?
谢谢。
更新1:感谢newacct,我的第一个关于属性的问题得到了解决。但是代码仍然无法正常工作。我发现扩展中的load()
方法并未执行。从 这个 答案的评论中,我了解到您的类需要是NSObject
的后代,但在我这种情况下,UINavigationBar
并不直接继承自NSObject
,但它确实实现了NSObjectProtocol
。所以我不知道为什么这仍然不起作用。另一种选择是添加@objc
,但Swift不允许您将其添加到扩展中。以下是更新后的代码。
问题仍未解决。
import Foundation
import UIKit
let FixedNavigationBarSize = "FixedNavigationBarSize";
extension UINavigationBar {
var fixedHeightWhenStatusBarHidden: Bool {
get {
return objc_getAssociatedObject(self, FixedNavigationBarSize).boolValue
}
set(newValue) {
objc_setAssociatedObject(self, FixedNavigationBarSize, NSNumber(bool: newValue), UInt(OBJC_ASSOCIATION_RETAIN))
}
}
func sizeThatFits_FixedHeightWhenStatusBarHidden(size: CGSize) -> CGSize {
if UIApplication.sharedApplication().statusBarHidden && fixedHeightWhenStatusBarHidden {
let newSize = CGSizeMake(self.frame.size.width, 64)
return newSize
} else {
return sizeThatFits_FixedHeightWhenStatusBarHidden(size)
}
}
override public class func load() {
method_exchangeImplementations(class_getInstanceMethod(self, "sizeThatFits:"), class_getInstanceMethod(self, "sizeThatFits_FixedHeightWhenStatusBarHidden:"))
}
}
更新 2: Jasper帮我实现了期望的功能,但显然它带来了一些重大缺点。
由于扩展中的load()
方法没有触发,正如Jasper所建议的那样,我将以下代码块移动到应用程序委托的didFinishLaunchingWithOptions
方法中。
method_exchangeImplementations(class_getInstanceMethod(UINavigationBar.classForCoder(), "sizeThatFits:"), class_getInstanceMethod(UINavigationBar.classForCoder(), "sizeThatFits_FixedHeightWhenStatusBarHidden:"))
现在我不得不在fixedHeightWhenStatusBarHidden
属性的getter方法中将返回值硬编码为“true”,因为现在交换代码在应用程序委托中执行,无法从视图控制器中设置值。这使得扩展在可重用性方面变得多余。
因此,问题或多或少仍然存在。如果有人有改进的想法,请回答。
UINavigationBar
?使用自定义的UINavigationBar
子类可以轻松实现此功能。UINavigationController
的文档中提供了有关使用自定义UINavigationBar
子类的信息,@AlexPretzlav's answer 也提供了相关信息。 - Slipp D. Thompson