ios 兩個狀態(tài)欄 背景圖片不一樣 push過去正常顯示
返回(pop)回來,當(dāng)前的背景圖變成了push過去的那個導(dǎo)航欄的背景圖片.
用圖片演示:
1.這是控制器A:
2.設(shè)置push過去的控制器B:
3.點擊返回
后的控制器A:
為什么控制器A的導(dǎo)航欄的背景圖片變成了控制器B的?如何修改?
代碼奉上:自定義控制器
的所有代碼:
#import "LMSNavigationController.h"
@interface LMSNavigationController ()
@end
@implementation LMSNavigationController
- (void)viewDidLoad {
[super viewDidLoad];
[self.navigationBar setTitleTextAttributes:
@{NSFontAttributeName:[UIFont systemFontOfSize:16]}];
}
/**
* 在這個方法中攔截所有push進(jìn)來的控制器
*/
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated
{
if (self.childViewControllers.count > 0) {
// 如果push進(jìn)來的不是第一個控制器
UIButton *leftBtn = [UIButton buttonWithType:UIButtonTypeCustom];
[leftBtn setImage:[UIImage imageNamed:@"nav-back.png"] forState:UIControlStateNormal];
[leftBtn setImage:[UIImage imageNamed:@"nav-back-hi.png"] forState:UIControlStateHighlighted];
leftBtn.frame = CGRectMake(0, 0, 30, 30);
[leftBtn addTarget:self action:@selector(popViewControllerAnimated:) forControlEvents:UIControlEventTouchUpInside];
viewController.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc]initWithCustomView:leftBtn];
// 隱藏tabbar
viewController.hidesBottomBarWhenPushed = YES;
}
//把導(dǎo)航欄底部的橫線去掉
[self.navigationBar setShadowImage:[UIImage new]];
// 這句super的push要放在后面, 讓viewController可以覆蓋上面設(shè)置的leftBarButtonItem
// 意思是,我們?nèi)稳豢梢灾匦略趐ush控制器的viewDidLoad方法中設(shè)置導(dǎo)航欄的leftBarButtonItem,如果設(shè)置了就會覆蓋在push方法中設(shè)置的“返回”按鈕,因為 [super push....]會加載push的控制器執(zhí)行viewDidLoad方法。
[super pushViewController:viewController animated:animated];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
控制器A關(guān)鍵代碼:
- (void)viewDidLoad {
[super viewDidLoad];
//導(dǎo)航欄透明背景(nav-clearcolor-image是一張透明的圖片)
[self.navigationController.navigationBar setBackgroundImage:[UIImage imageNamed:@"nav-clearcolor-image"] forBarMetrics:UIBarMetricsDefault];
//把導(dǎo)航欄底部的橫線去掉
[self.navigationController.navigationBar setShadowImage:[UIImage new]];
//不顯示文字
self.navigationItem.title = nil;
}
控制器B關(guān)鍵代碼:
- (void)viewDidLoad {
[super viewDidLoad];
UILabel *titleLabel = [[UILabel alloc]init];
titleLabel.text = @"push過來的控制器";
titleLabel.textColor = TitleTextColor;
[titleLabel sizeToFit];
self.navigationItem.titleView = titleLabel;
}
歡迎選擇我的課程,讓我們一起見證您的進(jìn)步~~
This is a question about the life cycle of UINavigationController
(assuming your LMSNavigationController
is its subclass) and UIViewController
(hereinafter referred to as VC). . . UINavigationController
(假設(shè)你們的 LMSNavigationController
是它的子類)以及 UIViewController
(后文簡稱 VC )生命周期的問題。。。
把 VC A 的 viewDidLoad
改成 viewWillAppear
。
(下面還有個感覺上更優(yōu)的辦法。)
先看看文檔對 viewDidLoad 是怎么描述的:
Called after the controller'??s view is loaded into memory.
在 VC 的視圖加載進(jìn)內(nèi)存的時候,這個方法會被調(diào)用。VC B pop
出去的時候不符合調(diào)用 VC A 的 viewDidLoad
的條件,解釋如下:
UINavigationController
維護(hù)著一個 VC 棧,你 push
、pop
那些 VC 時都是在操作這個棧。
push
的時候它會創(chuàng)建一個新的 VC 壓入棧中,就是你的 VC B,這個過程中這個新的 VC B 綁定的 view
經(jīng)歷了被加入內(nèi)存的過程, viewDidLoad
被調(diào)用。 VC B 處于棧頂,成為 topViewController
。 VC A 不再處于棧頂,但仍處于棧中,與它關(guān)聯(lián)的 view
仍在內(nèi)存中。再 pop
VC B 出去的時候,VC A 關(guān)聯(lián)的 view 的 viewDidLoad
不再被調(diào)用。
push
pop
具體調(diào)用了什么?上圖
Figure 1-5 Messages sent during stack changes
圖片來源:Navigation Controller 文檔的 Monitoring Changes to the Navigation Stack 部分
Monitoring Changes to the Navigation Stack
監(jiān)控導(dǎo)航棧的變化
以 push
VC B 出去為例:
VC B 作為當(dāng)前的 Topmost view controller ,其 viewWillDispear
最先被調(diào)用
VC A 的 viewWillAppear
被調(diào)用
UINavigationControllerDelegate
的 navigationController:willShowViewController:animated:
被調(diào)用
轉(zhuǎn)場動畫(完成?不清楚)
VC B 的 viewDidDispear
被調(diào)用
VC A 的 viewDidAppear
被調(diào)用
UINavigationControllerDelegate
的 navigationController:didShowViewController:animated:
viewDidLoad
to viewWillAppear
. ??Called after the controller's view is loaded into memory.????This method will be called when the VC view is loaded into memory. VC B
pop
does not meet the conditions for calling VC A's viewDidLoad
when it goes out. The explanation is as follows: ??
??UINavigationController
maintains a VC stack. When you push
and pop
those VCs, you are operating this stack. ??
??When push
, it will create a new VC and push it onto the stack, which is your VC B. In this process, this new VC B > The bound view
undergoes the process of being added to the memory, and viewDidLoad
is called. VC B is on top of the stack and becomes topViewController
. VC A is no longer on top of the stack, but still on the stack, and its associated view
is still in memory. When pop
VC B goes out, the viewDidLoad
of the view associated with VC A will no longer be called. ??
push
pop
call? ??Monitoring Changes to the Navigation Stack??Take
Monitoring changes to the Navigation Stack??
push
VC B going out as an example: ??
viewWillDispear
is called first??viewWillAppear
is called??UINavigationControllerDelegate
's navigationController:willShowViewController:animated:
is called??viewDidDispear
is called??viewDidAppear
is called??UINavigationControllerDelegate
's navigationController:didShowViewController:animated:
is called??In summary, VC A’s viewDidLoad
can be changed to viewWillAppear
. viewDidLoad
改成 viewWillAppear
即可。
然而個人感覺更好的辦法是把兩個 viewDidLoad
都拆了,邏輯重寫在 UINavigationControllerDelegate
的 navigationController:willShowViewController:animated:
中。即可在一個位置解決改背景圖這個需求。
完。
更新,上面說的用 UINavigationControllerDelegate
的辦法:
func navigationController(navigationController: UINavigationController, willShowViewController viewController: UIViewController, animated: Bool) {
if self.childViewControllers.count > 1 {
navigationController.navigationBar.setBackgroundImage(UIImage(named: "a"), forBarMetrics: .Default)
} else {
navigationController.navigationBar.setBackgroundImage(UIImage(named: "b"), forBarMetrics: .Default)
}
}
viewWillAppear
viewDidLoad
and rewrite the logic in UINavigationControllerDelegate
's navigationController:willShowViewController:animated:
middle. You can solve the need to change the background image in one place. End.
UINavigationControllerDelegate
as mentioned above: rrreee
viewWillAppear
I also tried it, it is exactly the same as this one, no black box appears. As far as this question is concerned, these two places meet your requirements. Just choose what you like. ??
??The navigation controller that comes with the system has already done what it needs to do before the animation starts, so there will be no picture loading until halfway through the animation. The worst thing is that the animation will be stuck for a few seconds before it starts, and it won't start until it is loaded. ??
??Your navigation controller is customized. Check the customized part to see if there are any black boxes caused by problems. ??
?? (Also... I still don’t see where the background image has been changed. It’s not the button image that was changed on the first controller) ??All VCs under nav use the same navBar
You modified the navBar when entering B
but did not change it back when exiting B
You have two navigation bar controllers (pop). The navigation bar returned is the same as the current navigation bar. You should create a proxy and reassign the value. (But it’s more troublesome)
Try setting the background image of vc again in the viewWillAppear method of A