前言
這篇文章主要記錄在我在開發(fā)中針對 UIWindow 的使用。
遇到的問題
通常境況下,我在新建一個新的 iOS 項目后,每次都會刪除 main.storyboard 這個文件。然后自己在 AppDelegate 中自己來創(chuàng)建一個 window 對象。大致就是下面這個樣子的:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
self.window.backgroundColor = [UIColor blueColor];
self.window.rootViewController = [ViewController new];
[self.window makeKeyAndVisible];
return YES;
}
最近在項目中遇到一個場景:
App 啟動后,此時需要 App 進行強制更新。強制更新,就要求強制更新的按鈕在最頂層,我發(fā)現(xiàn)之前代碼是通過 [UIApplication sharedApplication].delegate.window 獲取到 window 對象,并在此之上添加強制更新的視圖作為它的子視圖。貌似好像沒有什么問題,其實不然。因為這個強制更新的視圖不一定是在最頂層的。因為 Modal 出來的 Controller 會把它蓋住。不信你就試試,這樣一來可以進行別的操作算哪門子的強制更新?
解決方案
既然 KeyWindow 解決不了這個問題,我的解決方案是通過自定義 window,并設(shè)置 window 的級別,這樣他就在最頂層了。而自己創(chuàng)建一個 window 對象是有一些小細節(jié)的。還是通過代碼具體看一下:
我打算怎么設(shè)計
- 自定義
YMUpdateView繼承自UIView,提供一個show接口 - 重寫
\- (**instancetype**)initWithFrame:(CGRect)frame方法,自定義UI視圖,主要就是自定義window對象。window里面的子視圖,可以根據(jù)自己的業(yè)務(wù)和UI設(shè)計稿進行自己定制
我的實現(xiàn)
部分代碼如下:
#import "YMUpdateView.h"
@interface UpdateView ()
@property (nonatomic, strong) UIWindow *window;
@end
@implementation UpdateView
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
_window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
_window.windowLevel = UIWindowLevelStatusBar;
_window.rootViewController = [[UIViewController alloc] init];
_window.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.6];
}
return self;
}
- (void)show {
_window.hidden = NO;
}
@end
- 核心代碼就是
\- (**instancetype**)initWithFrame:(CGRect)frame中自己創(chuàng)建一個window對象。更好一點可以封裝一個方法專門來創(chuàng)建 UI 視圖。在layoutSubviews方法中進行布局。 - 注意一點就是,window 對象必須是被強引用的
-
windowLevel設(shè)置為UIWindowLevelStatusBar級別,它和狀態(tài)欄在一個級別,一定是在最頂層的 - 在使用的時候,也要用
strong修飾的屬性,進行強引用。
@interface ViewController ()
@property (nonatomic, strong) UpdateView *uv;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.uv = [[UpdateView alloc] init];
[self.uv show];
// 模擬出現(xiàn) modal Controller 蓋住的情況
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
TestViewController *vc = [[TestViewController alloc] init];
vc.modalPresentationStyle = UIModalPresentationFullScreen;
[self presentViewController:vc animated:YES completion:nil];
});
} /* viewDidLoad */
結(jié)束語
東西不難,但在工作中還比較實用。這只是一個簡單的場景。我們經(jīng)常在一些 App 中見到懸浮球的功能,我覺得也可以通過自定義 window 對象來實現(xiàn),需要處理的是手勢和邊界的計算。