据我所知,最初未出现的自定义背景图像在 iOS7 GM 或最终版本中并未修复。我看到了同样的问题。它似乎确实是一个 Apple 错误。Apple 使用的私有视图在初始显示时需要它时根本不会得到 setNeedsDisplay 调用。对它做任何导致该调用的事情都应该修复它——比如按下它(这可能会改变内部状态,因此它会在自身上调用 setNeedsDisplay),或者启动一个模式(这可能会强制在下一次重新显示整个视图层次结构) viewWillAppear:调用)。
使用 leftBarItems 代替也可以工作,但这可能会导致现有代码的大量维护问题(例如,某些屏幕可能有自己的左侧项目,期望当设置回 nil 时它们会恢复原始的后面项目)。
如前所述,理想情况下,您可以在 iOS7 上更改为无边框外观,这意味着该错误并不明显(因为没有背景图像)。但是,对于某些 iOS6/iOS7 过渡情况,这可能会很困难(很多屏幕,和/或需要一段时间支持较旧的 iOS 版本,并且很难实现两个外观,而且如果没有其他外观,它看起来并不好无边框变化)。如果是这种情况,以下补丁应该可以工作:
#import <objc/runtime.h>
@implementation UINavigationBar (BackButtonDisplayFix)
+ (void)load
{
if ([UIDevice currentDevice].systemVersion.intValue >= 7)
{
/*
* We first try to simply add an override version of didAddSubview: to the class. If it
* fails, that means that the class already has its own override implementation of the method
* (which we are expecting in this case), so use a method-swap version instead.
*/
Method didAddMethod = class_getInstanceMethod(self, @selector(_displaybugfixsuper_didAddSubview:));
if (!class_addMethod(self, @selector(didAddSubview:),
method_getImplementation(didAddMethod),
method_getTypeEncoding(didAddMethod)))
{
Method existMethod = class_getInstanceMethod(self, @selector(didAddSubview:));
Method replacement = class_getInstanceMethod(self, @selector(_displaybugfix_didAddSubview:));
method_exchangeImplementations(existMethod, replacement);
}
}
}
- (void)_displaybugfixsuper_didAddSubview:(UIView *)subview
{
[super didAddSubview:subview];
[subview setNeedsDisplay];
}
- (void)_displaybugfix_didAddSubview:(UIView *)subview
{
[self _displaybugfix_didAddSubview:subview]; // calls the existing method
[subview setNeedsDisplay];
}
@end
注意: UINavigationBar 当前确实覆盖了相关方法,因此我希望使用 method_exchangeImplementations 样式。为了安全起见,我只是添加了其他内容,以防 Apple 更改他们的代码。我们自己可能会变得无边界,但我确实发现这种方法可以作为一种选择(直到更彻底的 UI 提升),至少。
附加说明:此错误似乎已在 iOS 7.1 中修复。因此,可以将补丁设置为仅在运行 >= 7.0 和 < 7.1 时安装方法。