Es gibt ein kleines Problem mit UINavigationBar
, die ich versuche zu überwinden. Wenn Sie die Statusleiste mit der Methode prefersStatusBarHidden()
in einem View-Controller ausblenden (ich möchte die Statusleiste für die gesamte App nicht deaktivieren), verliert die Navigationsleiste 20pt ihrer Höhe, die zur Statusleiste gehört. Grundsätzlich schrumpft die Navigationsleiste.Methode Swizzling in Swift
ich verschiedene Abhilfen versuchte, aber ich fand, dass jeder von ihnen Nachteile hatte. Dann stieß ich auf diese category, die mit der Methode Swizzling, fügt eine Eigenschaft namens fixedHeightWhenStatusBarHidden
in die UINavigationBar
Klasse, die dieses Problem löst. Ich habe es in Objective-C getestet und es funktioniert. Hier sind die header und die implementation des ursprünglichen Objective-C-Codes.
Jetzt, da ich meine App in Swift mache, habe ich versucht, es in Swift zu übersetzen.
Das erste Problem, mit dem ich konfrontiert wurde, war Swift Extension kann keine gespeicherten Eigenschaften haben. Also musste ich mich mit der berechneten Eigenschaft begnügen, um die fixedHeightWhenStatusBarHidden
Eigenschaft zu deklarieren, die es mir ermöglicht, den Wert festzulegen. Aber das löst ein anderes Problem aus. Anscheinend können Sie berechneten Eigenschaften keine Werte zuweisen. Wie so.
self.navigationController?.navigationBar.fixedHeightWhenStatusBarHidden = true
Ich erhalte die Fehler Kann nicht auf das Ergebnis dieses Ausdrucks zuweisen.
Wie auch immer, unten ist mein Code. Es kompiliert ohne Fehler, aber es funktioniert nicht.
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()
Methode in der Mitte wird kommentiert, weil es mich verlassen Fehler ein Verfahren Neudeklaration gibt.
Ich habe nicht Methode Swizzling in Swift oder Objective-C vor, so dass ich nicht sicher bin, der nächste Schritt, um dieses Problem zu lösen oder sogar überhaupt möglich ist.
Kann jemand bitte etwas Licht darauf werfen?
Vielen Dank.
UPDATE 1: Dank newacct, meine erste Frage über Eigenschaften gelöst wurde. Aber der Code funktioniert immer noch nicht. Ich habe festgestellt, dass die Ausführung die load()
Methode in der Erweiterung nicht erreicht. Von Kommentaren in this Antwort, habe ich gelernt, dass entweder Ihre Klasse von NSObject
, die in meinem Fall UINavigationBar
nicht direkt von NSObject
abstammt abgeleitet werden muss, aber es implementiert NSObjectProtocol
. Ich bin also nicht sicher, warum das immer noch nicht funktioniert. Die andere Option ist das Hinzufügen von @objc
, aber Swift erlaubt es nicht, es zu Erweiterungen hinzuzufügen. Unten ist der aktualisierte Code.
Das Problem ist noch offen.
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:"))
}
}
UPDATE 2: Jasper hat mir geholfen, um die gewünschte Funktionalität zu erreichen, aber anscheinend kommt es mit ein paar große Nachteile.
Da die Methode load()
in der Erweiterung nicht ausgelöst wurde, wie Jasper vorgeschlagen hat, habe ich den folgenden Codeblock in die Methode didFinishLaunchingWithOptions
der App-Delegierten verschoben.
method_exchangeImplementations(class_getInstanceMethod(UINavigationBar.classForCoder(), "sizeThatFits:"), class_getInstanceMethod(UINavigationBar.classForCoder(), "sizeThatFits_FixedHeightWhenStatusBarHidden:"))
Und ich hatte den Rückgabewert auf ‚true‘ in dem Getter von fixedHeightWhenStatusBarHidden
Eigenschaft codieren, weil jetzt, dass der Swizzling Code in der AppDelegate ausführt, können Sie nicht einen Wert aus einem View-Controller eingestellt. Dies macht die Erweiterung überflüssig, wenn es um die Wiederverwendbarkeit geht.
So ist die Frage immer noch mehr oder weniger offen. Wenn jemand eine Idee hat, es zu verbessern, bitte antworte.
Warum Swizzling Sie 'UINavigationBar'? Sie können dies leicht mit einer benutzerdefinierten Unterklasse von 'UINavigationBar' tun. Die Dokumentation für ['UINavigationController'] (https://developer.apple.com/library/ios/documentation/UIKit/Reference/UINavigationController_Class/) enthält Informationen zur Verwendung einer benutzerdefinierten Unterklasse 'UINavigationBar', ebenso wie [AlexPretzlavs Antwort] (http://stackoverflow.com/questions/25651081/method-swizzling-in-swift#26641469). –