UIWindow 实现遮盖导航条的蒙版
使用代码构建应用的主界面
我们先来介绍一下,如何使用代码来构建项目的主界面,以及主界面的一般架构方式
- 概述
- 刚创建的 iOS 项目默认是使用 Main.storeboard 作为项目的主界面的
- 若你不理解什么是主界面,那么请把它当成是应用启动后显示在用户的眼前的这个界面,通常是一个基于 UITabBarController 的界面。
请原谅我的无知
- 若你不理解什么是主界面,那么请把它当成是应用启动后显示在用户的眼前的这个界面,通常是一个基于 UITabBarController 的界面。
- 在通常的项目中,我们是不使用 StoreBoard,一般使用 代码 和 xib 结合的方式开发,也有人使用纯代码的方式开发。个人比较喜欢纯代码的方式开发项目。各有利弊在次不再赘述。
- 刚创建的 iOS 项目默认是使用 Main.storeboard 作为项目的主界面的
- 如何构建无 StoreBoard 的项目
删除 StoreBoard
StoreBoard 所处的文件夹,如图:

删除 main.toreBoard ,选中 main.toreBoard 点击 delete 键,选择 “Move to Trash”,如图:

更改项目设置,使其不以 Main.storeboard 作为主界面。如图:

效果,此时启动项目将会看到应用的主界面一片漆黑,应为应用找不到主界面来显示。如图:

使用代码构建项目入口
关于 AppDelegate
- AppDelegate 是整个应用的代理,应用从启动到关闭的整个过程中的多数时间都会通知代理,如:加载应用的主界面,应用即将进入后台,内存警告等。在此不再介绍关于 AppDelegate 更多的知识,若有机会,我会用一篇博客的特意介绍 AppDelegate 那些事。
AppDelegate 中的 window
应用在启动的时候,会先检测是否以 Main.storeboard 作为主界面,若没有 Main.storeboard ,将会使用 AppDelegate 的 window 作为主界面
设置 AppDelegate 中 window 的背景色,验证 AppDelegate 中的 window 在应用中的作用
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// 初始化 window
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
self.window.backgroundColor = [UIColor whiteColor];
// 显示 window
[self.window makeKeyAndVisible];
return YES;
}

如图所示,项目启动后的主界面是白色的,但是此时应用已经 crash,原因如图:

- 意思是:应用程序的窗口(windows)在应用程序加载结束时期望得到一个根控制器(若达不到,就会崩溃哦)
设置 AppDelegate 中的 window 的根控制器
// 设置 window 的根控制器
IDTabBarController *tabBarController = [[IDTabBarController alloc] init];
self.window.rootViewController = tabBarController;
- 常用的主界面架构
- 通常情况下,应用的主界面是 UITabBarController 管理下的多个(通常不超过四个) UINavigationController。
- 架构应用的主界面
搭建项目的文件结构,如图所示:

创建应用中每个模块的控制器(共4个模块)
微信(Wechat)
@implementation IDWechatViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 设置 tabBar 和 navigationBar 的 title
self.title = @"微信";
}
@end
通讯录(Contacts)
@implementation IDContactsViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.title = @"通讯录";
}
@end
发现(Discovery)
@implementation IDDiscoveryViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.title = @"发现";
}
@end
我(Mine)
@implementation IDMineViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.title = @"我";
}
@end
将各个模块的中跟控制器添加为 tabBarController 的 childViewController
不在 tabBarController 中设置 childViewController 的 item(学习一下方法的封装哦)
- (void)viewDidLoad {
[super viewDidLoad];
// 设置 tabBar 的子控制器
[self setChildViewControllers];
}
/** 设置 tabBar 的子控制器 */
- (void)setChildViewControllers {
// 添加 tabBar 中所有的自控制器
for (int i = 0; i < self.childViewControllers.count; i++) {
[self addChildViewController:self.childViewControllers[i] withTitle:@"" imageName:@"" selectedImageName:@""];
}
}
/** 添加每一个控制器为 tabBar 的 childViewController */
- (void)addChildViewController:(UIViewController *)viewController withTitle:(NSString *)title imageName:(NSString *)imageName selectedImageName:(NSString *)selectedImageName {
// 设置每个控制器对应的 tabBarItem
viewController.tabBarItem = [[UITabBarItem alloc] initWithTitle:title image:[UIImage imageNamed:imageName] selectedImage:[UIImage imageNamed:selectedImageName]];
// 将每个模块的主控制器包装成导航控制器
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:viewController];
// 将每个模块的主控制器添加为 tabBarController 的 childViewController
[self addChildViewController:navigationController];
}
运行项目,并不是所有的子控制器标签全部显示到主屏幕窗口,如图:

在 tabBarController 中设置 childViewController 的 item,修改方法 setChildViewControllers
关于更多设置 item 的细节,再次不再赘述,大家可以自己琢磨一下。若有任何疑问,都可以联系我/** 设置 tabBar 的子控制器 */
- (void)setChildViewControllers {
// 添加 tabBar 中所有的自控制器
for (int i = 0; i < self.childViewControllers.count; i++) {
[self addChildViewController:self.childViewControllers[i] withTitle:self.titlesArray[i] imageName:@"mine_cust" selectedImageName:@""]; // 修改
}
}
/** 添加每一个控制器为 tabBar 的 childViewController */
- (void)addChildViewController:(UIViewController *)viewController withTitle:(NSString *)title imageName:(NSString *)imageName selectedImageName:(NSString *)selectedImageName {
// 设置每个控制器对应的 tabBarItem
UITabBarItem *item = [[UITabBarItem alloc] initWithTitle:title image:[UIImage imageNamed:imageName] selectedImage:[UIImage imageNamed:selectedImageName]];
viewController.tabBarItem = item;
// 若你未设置 tabBarItem , title 会同时作用于 tabBarItem 和 navigationItemd 的 item
viewController.title = title; // 在 item 中已经设置过了
// 将每个模块的主控制器包装成导航控制器
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:viewController];
// 将每个模块的主控制器添加为 tabBarController 的 childViewController
[self addChildViewController:navigationController];
}
运行项目,所有的子控制器标签全部显示到主屏幕窗口,如图:

蒙版
很抱歉,扯了一些题外话,但希望可以对童鞋们,有所帮助。接下来进入主体。
- 概述
- 蒙版就是一种遮罩,盖在当前控制器上,阻止用户对当前控制器界面进行交互。通常的弹框空间后面会有一层蒙版
- 实现思路
- 在此,使用一个 window 来作为蒙版,主要原因如下:
- window 存在 windowLevel 属性,通过控制级别可以控制显示的层次
- window 是一个容器,可以容纳其他的控件
- window 的显示和隐藏极其方便
- 关于蒙版 window
- 在这里我们使用继承自 UIWindow 的单例,来实现蒙版 window,若你对单例设计模式不太了解,请参看一下文章:
- 关于 window 的 windowLevel
UIWindowLevelNormal
普通级别,可以遮盖导航条,但是无法遮盖状态栏,如图

UIWindowLevelAlert
可以遮盖状态栏,如图

UIWindowLevelStatusBar
- 最高级别
- 蒙版的使用方法
- 提供方法 show 和 hide 来显示和隐藏蒙版
- 在此,使用一个 window 来作为蒙版,主要原因如下:
- 具体实现
单例实现蒙版 window
在这里使用单例,或许不是一种好的选择,但是我们在此不讨论#pragma mark - 单例所需要实现的方法
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:[UIScreen mainScreen].bounds]) {
}
return self;
}
+ (instancetype)shareIDMasking {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_idMasking = [[self alloc] init];
});
return _idMasking;
}
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_idMasking = [super allocWithZone:zone];
});
return _idMasking;
}
- (id)copyWithZone:(NSZone *)zone
{
return _idMasking;
}
暴露接口
#pragma mark - 蒙版的显示与隐藏
- (void)show {
// 显示 蒙版 window
[self makeKeyAndVisible];
}
- (void)hide {
// 移除所有的子控件
for (UIView *view in [self subviews]) {
[view removeFromSuperview];
} // 将 蒙版 window 的 windowLevel 置为 nomal,否则其他的 window 无法显示出来
self.windowLevel = UIWindowLevelNormal;
// 先是应用主界面的 window
[[[UIApplication sharedApplication].delegate window] makeKeyAndVisible];
}
蒙版的使用
@implementation IDWechatViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 设置 “Hide” 按钮
[self setupHidenButton];
}
/** 设置 “Hide” 按钮 */
- (void)setupHidenButton {
self.hidedButton = [[UIButton alloc] initWithFrame:CGRectMake(180, 264, 70, 44)];
self.hidedButton.backgroundColor = [UIColor blueColor];
[self.hidedButton setTitle:@"Hide" forState:UIControlStateNormal];
[self.hidedButton addTarget:self action:@selector(buttonClick:) forControlEvents:UIControlEventTouchUpInside];
}
/** 点击控制器的 view 弹出蒙版 */
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[self setupMaskingAndShow];
}
/** 隐藏蒙版 */
- (void)buttonClick:(UIButton *)button {
[self.maskingWindow hide];
}
/** 设置蒙版并显示出来 */
- (void)setupMaskingAndShow {
self.maskingWindow = [IDMasking shareIDMasking];
// 设置 maskingWindow 的等级
self.maskingWindow.windowLevel = UIWindowLevelAlert;
self.maskingWindow.backgroundColor = [UIColor redColor];
[self addSubviewsToMasking];
// 显示 蒙版
[self.maskingWindow show];
}
/** 向蒙版中添加子控件 */
- (void)addSubviewsToMasking {
[self.maskingWindow addSubview:self.hidedButton];
}
@end
效果,如图:

由于篇幅限制,Blog 中只提供了核心代码。若有需要完整工程文件的,请联系我,谢谢您的理解和支持。若您觉得有帮助,别忘了点击下方的推荐哦!
UIWindow 实现遮盖导航条的蒙版的更多相关文章
- Bootstrap之导航条
基本导航条 <!-- navbar-inverse相反颜色风格 --> <!-- navbar-static-top去除圆角 --> <!-- navbar-fixed- ...
- bootstrap学习笔记<十一>(导航条)
基础导航条.样式:class="navbar navbar-default",属性:role="navigation" <div class=" ...
- iOS:导航栏的工具条和导航条
功能:用NAV视图控制器打开新的视图,默认工具条和导航条隐藏,双击显示之 // // main.m // Hello // // Created by lishujun on 14-8-28. // ...
- iOS viewController添加导航条以及返回跳转选择
给单独的viewcontroller或者在Appdelegate的主页面添加导航条,只要在viewcontroller上添加navigationcontroller,在添加此navigationcon ...
- Swift - 使用导航条和导航条控制器来进行页面切换
通过使用导航条(UINavigationBar)与导航条控制器(UINavigationController)可以方便的在主页面和多层子页面之间切换.下面通过一个简单“组件效果演示”的小例子来说明如何 ...
- Bootstrap每天必学之导航条
http://www.jb51.net/article/75534.htm Bootstrap每天必学之导航条,本文向大家讲解了多种多样的导航条,以及导航条中元素的实现方法,感兴趣的小伙伴们可以参考一 ...
- 使用CSS3制作导航条和毛玻璃效果
导航条对于每一个Web前端攻城狮来说并不陌生,但是毛玻璃可能会相对陌生一些.简单的说,毛玻璃其实就是让图片或者背景使用相应的方法进行模糊处理.这种效果对用户来说是十分具有视觉冲击力的. 本次分享的主题 ...
- JQM (功能栏、导航条)
在Mobile中导航条的基本结构: <div data-role="navbar"> ul>li>a </div> 其中含有“行(grid)”和 ...
- css制作漂亮彩带导航条菜单
点击这里查看效果:http://keleyi.com/keleyi/phtml/divcss/17.htm 效果图: 以下是源代码: <!DOCTYPE html PUBLIC "-/ ...
随机推荐
- List<T>保存为XML文件
今天我们学习怎样把List<T>写成一个XML文件保存起来.因为我们在做动态网站开发时,需要对一些不太常变化的数据产生为XML文件,让程序直接去读取,而不是每次是SQL数据库取. 为了解决 ...
- matlab 调用dos命令和文件操作
第一.利用!直接调用,简单方便,可以带操作对象:!del A.bat 第二.调用system函数或者dos函数,既可以实现功能,又返回参数,能检查执行情况,方便后面程序的开发,推荐这个 [status ...
- 损失函数(Loss Function) -1
http://www.ics.uci.edu/~dramanan/teaching/ics273a_winter08/lectures/lecture14.pdf Loss Function 损失函数 ...
- 如何显示二进制流的图片(利用img控件)
之前在http://www.cnblogs.com/JsonZhangAA/p/5568575.html博文中是利用的image控件来显示的二进制流图片,我现在想的是能 通过普通的<img id ...
- 迷信AgainAndAgain
又重新在VBox中安装Debian其它镜像两次,依然在安装桌面软件包时挂掉...
- [javaSE] 反射-获取类的成员属性和构造方法
成员属性和构造方法皆为对象,通过Class对象的方法可以得到 package com.tsh.reflect; import java.lang.reflect.Constructor; import ...
- PHP 批量生成静态文件目录代码
<?php /** * @author:jiangzaixing 20160314 * 获取静态文件方法 */ class StaticFile { const MAP_FILE_NAME = ...
- android 去掉标题
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FUL ...
- 搭建自己的ngrok服务(国内直接可用http://qydev.com/#)
ngrok 服务可以分配给你一个域名让你本地的web项目提供给外网访问, 特别适合向别人展示你本机的web demo 以及调试一些远程的API (比如微信公众号,企业号的开发) ngrok的官方服务可 ...
- 值得 Web 开发人员收藏的16款 HTML5 工具
HTML5 正在迅速改变创建和管理网站的方式.HTML5 在不同的领域让网页设计更强大的.快速,安全,响应式,互动和美丽,这些优点吸引更多的 Web 开发人员使用 HTML5 开发各种网站和应用程序. ...