iOS UIWindow 覆盖 StatusBar

栏目: IOS · 发布时间: 5年前

内容简介:最近产品要做一个消息的通知,而且通知是覆盖在 StatusBar 上面的。如果是普通的 UIView 则肯定是不行的,因为 StatusBar 为系统全局性的视图,所以要想覆盖它,则必须为 Statusbar 类型的,那么也就是 UIWindow 了。window等级,即window在z轴上的层级关系,默认是0。UIWindowLevel 本身是一个 CGFloat 类型,可以随意设置或进行加减,高等级会显示在低等级上面。系统给出了三种常用等级:这样创建的与 statusbar 大小一样的UIWindow

最近产品要做一个消息的通知,而且通知是覆盖在 StatusBar 上面的。如果是普通的 UIView 则肯定是不行的,因为 StatusBar 为系统全局性的视图,所以要想覆盖它,则必须为 Statusbar 类型的,那么也就是 UIWindow 了。

UIWindow 的基础介绍

  • UIWindow是一种特殊的UIView,通常在一个app中至少会有一个UIWindow。
  • iOS程序启动完毕后,创建的第一个视图控件就是UIWindow,接着创建控制器的View,最后将控制器的View添加到UIWindow上,于是控制器的View就显示在屏幕上了。
  • 一个iOS程序之所以能显示在屏幕上,完全是因为它有UIWindow,也就是说,没有UIWindow就看不到任何UI界面。
  • 状态栏和键盘都是特殊的UIWindow。

这里有三个重要的对象UIScreen,UIWindow,UIView。

  1. UIScreen对象识别物理屏幕连接到设备
  2. UIWindow对象提供绘画支持给屏幕
  3. UIView执行绘画,当窗口要显示内容的时候,UIView绘画出他们的内容并附加到窗口上。

UIWindow 等级

window等级,即window在z轴上的层级关系,默认是0。UIWindowLevel 本身是一个 CGFloat 类型,可以随意设置或进行加减,高等级会显示在低等级上面。系统给出了三种常用等级:

UIKIT_EXTERN const UIWindowLevel UIWindowLevelNormal;      0
UIKIT_EXTERN const UIWindowLevel UIWindowLevelAlert;       2000
UIKIT_EXTERN const UIWindowLevel UIWindowLevelStatusBar;   4000

初始化 UIWindow 覆盖 StatusBar

-(void)initWindow {
  //初始化statusView,可在其上添加控件
  CGRect statusBarFrame = [UIApplication sharedApplication].statusBarFrame;
  stateWindow = [[UIWindow alloc] initWithFrame:statusBarFrame];
  // 设置windowLevel为statusbar + 1 保证可以显示在statusbar上面
  stateWindow.windowLevel = UIWindowLevelStatusBar + 1;
  stateWindow.backgroundColor = [UIColor orangeColor];
  stateWindow.userInteractionEnabled = NO;
}

这样创建的与 statusbar 大小一样的UIWindow 已经好了,默认创建好 这个UIWindow 则已经添加上去了,只是默认不显示,可以使用下面来控制显示和隐藏。

window.hidden = YES; 
window.hidden = NO;

当然 UIwindow 还有个 makeKeyAndVisible 方法,这个方法会将新建的 UIWindow 设置为主窗口并显示,之后如果消失后,需要将原来的主窗口设置回来,不然会出现很多异常的问题,这里切记。

注意:控制新添加的 UIWindow 使用 hidden 来控制。尽量不要使用 makeKeyAndVisible

这里的 stateWindow 必须是私有变量或者全局变量,生命周期随所在控制器的生命周期。

添加Label

上面的 UIWindow 创建好了,那么要显示相关的提示文字,还需要添加 label,

label = [[UILabel alloc] initWithFrame:stateWindow.frame];
label.backgroundColor = [UIColor blackColor];
label.textColor = [UIColor whiteColor];
label.font=[UIFont systemFontOfSize:12];
label.textAlignment = NSTextAlignmentCenter;
[stateWindow addSubview:label];

之后设置 label的文字即可进行对其内容控制。

旋转问题处理

上面弄完基本上都完成,但是在旋转屏幕后,发现显示还是在原来的位置上,无法跟随系统的状态栏一起旋转。需要对 Window 设置空的UIViewController后才会跟着状态栏旋转。

// 需要设置一个空的ViewController 不然旋转屏幕后,不会跟着旋转坐标系
stateWindow.rootViewController = [UIViewController new];

旋转后,又发现了新的问题,在新建的 UIWindow 根据的是一开始时的状态长宽,但是旋转为横屏时,尺寸会发生变化,所以在每次显示 statusWindow 时重新设置下frame的大小,如下:

CGRect newFrame = CGRectMake(0, 0, [[UIScreen mainScreen] bounds].size.width, STATUSBAR_HEIGHT);
stateWindow.frame = newFrame;
label.frame = newFrame;

这里不直接取 statusbar 的frame,因为在statusbar 隐藏时获取的长宽为0,所以上面设置时取值为宽度和statusbar的高度,高度在一开始进行获取保存进常量中。

综上:对于显示覆盖 statusbar 的 UIWindow 已经完成啦,

其他细节

当我们显示了之后一般需要在延迟几秒后进行隐藏,在 Android 中一般实用Handler进行,或者实用timer进行执行操作。那么 ios 中怎么实用呢? 请看如下方法:

//延迟 3s 后执行 hideStateMsg 方法。
 [self performSelector:@selector(hideStateMsg) withObject:nil afterDelay:3.0];
 
 -(void)hideStateMsg {
  stateWindow.hidden = YES;
}

当然在执行之前可能还需要把之前的延时任务取消了,则有如下两种方法。

// 取消 self 对象中所有的延迟任务。
[NSObject cancelPreviousPerformRequestsWithTarget:self];

// 取消指定的函数的延迟执行操作。
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(hideStateMsg) object:nil];

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Go语言学习笔记

Go语言学习笔记

雨痕 / 电子工业出版社 / 2016-6 / 89

作为时下流行的一种系统编程语言,Go 简单易学,性能很好,且支持各类主流平台。已有大量项目采用 Go 编写,这其中就包括 Docker 等明星作品,其开发和执行效率早已被证明。本书经四年多逐步完善,内容覆盖了语言、运行时、性能优化、工具链等各层面知识。且内容经大量读者反馈和校对,没有明显的缺陷和错误。上卷细致解析了语言规范相关细节,便于读者深入理解语言相关功能的使用方法和注意事项。下卷则对运行时源......一起来看看 《Go语言学习笔记》 这本书的介绍吧!

URL 编码/解码
URL 编码/解码

URL 编码/解码

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试