iOS MMDrawerController源码解读(一)
提前说好,本文绝对不是教你如何使用MMDrawerController这个第三方库,因为那太多人写了 ,也太简单了。这篇文章主要带你分析MMDrawerController是怎么实现抽屉效果,明白第三方库的内部原理。例外,本人也封装了一个FHSegmentControl的第三方库,欢迎大家去看看啊。
1.MMDrawerController的实例化方法
先明确几个变量的意义。
// 中央控制器
@property (nonatomic, strong) UIViewController * centerViewController;
// 左侧控制器、右侧控制器,统称侧边控制器
@property (nonatomic, strong) UIViewController * leftDrawerViewController;
@property (nonatomic, strong) UIViewController * rightDrawerViewController;
我分析第三方库,都是从实例化方法开始的。那么多类,方法更多,必须有一个开始。从实例化方法开始,可以找出作者的思考方式,这里也就是怎么实现抽屉效果的。
// 1.
-(instancetype)initWithCenterViewController:(UIViewController *)centerViewController leftDrawerViewController:(UIViewController *)leftDrawerViewController rightDrawerViewController:(UIViewController *)rightDrawerViewController{NSParameterAssert(centerViewController);self = [super init];if(self){[self setCenterViewController:centerViewController];[self setLeftDrawerViewController:leftDrawerViewController];[self setRightDrawerViewController:rightDrawerViewController];}return self;
}
// 2.
-(instancetype)initWithCenterViewController:(UIViewController *)centerViewController leftDrawerViewController:(UIViewController *)leftDrawerViewController{return [self initWithCenterViewController:centerViewController leftDrawerViewController:leftDrawerViewController rightDrawerViewController:nil];
}
//3.
-(instancetype)initWithCenterViewController:(UIViewController *)centerViewController rightDrawerViewController:(UIViewController *)rightDrawerViewController{return [self initWithCenterViewController:centerViewController leftDrawerViewController:nil rightDrawerViewController:rightDrawerViewController];
}
一共有3个实例方法,第2.3个实例方法,最后都得调用第1个实例方法,所以我们只要分析第1个实例方法就可以了。第一个实例方法调用了三个方法。
// 4[self setCenterViewController:centerViewController];// 5[self setLeftDrawerViewController:leftDrawerViewController];// 6[self setRightDrawerViewController:rightDrawerViewController];
我们先看第5、6个方法。
```
-(void)setRightDrawerViewController:(UIViewController *)rightDrawerViewController{
[self setDrawerViewController:rightDrawerViewController forSide:MMDrawerSideRight];
}
-(void)setLeftDrawerViewController:(UIViewController *)leftDrawerViewController{
[self setDrawerViewController:leftDrawerViewController forSide:MMDrawerSideLeft];
}
  这两个方法其实都是调用了同一个方法:
- (void)setDrawerViewController:(UIViewController *)viewController forSide:(MMDrawerSide)drawerSide;
综上所述,我们要明白MMDrawerController是怎样创建的,只要明白下面的两个方法就可以了,顿时感觉工作量少了很多有没有。
// 1.添加中央控制器
-(void)setCenterViewController:(UIViewController *)centerViewController;
// 2.添加左右两边的控制器
- (void)setDrawerViewController:(UIViewController *)viewController forSide:(MMDrawerSide)drawerSide;
###2.添加中央控制器
// 1.
-(void)setCenterViewController:(UIViewController )centerViewController{
[self setCenterViewController:centerViewController animated:NO];
}
//2.直接看这个方法就好了,因为第一个方法也是调用这个方法
-(void)setCenterViewController:(UIViewController )centerViewController animated:(BOOL)animated{
// 如果将要添加的中央控制器和原来的一样,就不要再添加了
// self.centerViewController 已经添加的中央内容控制器。第一次实例化,为nil。
if ([self.centerViewController isEqual:centerViewController]) {
return;
}
// 添加中央内容视图,也就是:往self.childControllerContainerView上添加self.centerContainerView
if (_centerContainerView == nil) {
// self.childControllerContainerView 是一个添加在self.view 上面和self.view位置和大小一样的UIView。
CGRect centerFrame = self.childControllerContainerView.bounds;
if(self.centerContainerView == nil){
// MMDrawerCenterContainerView 先当做UIView,后面在慢慢分析
self.centerContainerView = [[MMDrawerCenterContainerView alloc] initWithFrame:centerFrame];
[self.centerContainerView setAutoresizingMask:UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight];
[self.centerContainerView setBackgroundColor:[UIColor clearColor]];
//开始时: self.openSide = MMDrawerSideNone;因为我们实例化的时候,并没有展示左右边两边的抽屉视图
[self.centerContainerView setOpenSide:self.openSide];
//开始时: self.centerHiddenInteractionMode = MMDrawerOpenCenterInteractionModeNavigationBarOnly;设置响应模式
[self.centerContainerView setCenterInteractionMode:MMDrawerOpenCenterInteractionModeNone];
[self.childControllerContainerView addSubview:self.centerContainerView];
}
}
// 因为要添加新的中央控制器,如果旧的存在,就要删除
UIViewController * oldCenterViewController = self.centerViewController;
if(oldCenterViewController){
[oldCenterViewController willMoveToParentViewController:nil];
if(animated == NO){
[oldCenterViewController beginAppearanceTransition:NO animated:NO];
}
[oldCenterViewController.view removeFromSuperview];
if(animated == NO){
[oldCenterViewController endAppearanceTransition];
}
[oldCenterViewController removeFromParentViewController];
}
// 添加新的中央控制器
_centerViewController = centerViewController;
[self addChildViewController:self.centerViewController];
[self.centerViewController.view setFrame:self.childControllerContainerView.bounds];
[self.centerContainerView addSubview:self.centerViewController.view];
// 把中央视图放在子视图容器最前面
[self.childControllerContainerView bringSubviewToFront:self.centerContainerView];
[self.centerViewController.view setAutoresizingMask:UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight];
// 设置阴影,以后讲
[self updateShadowForCenterView];
if(animated == NO){// 实例化的时候,这个方法不走// self.view.window 是判断是否添加到了手机屏幕上,也就是keyWindow上。if(self.view.window) {[self.centerViewController beginAppearanceTransition:YES animated:NO];[self.centerViewController endAppearanceTransition];}//告诉系统有一个视图控制器从容器中添加或者移除[self.centerViewController didMoveToParentViewController:self];
}
}
  其实这里一共有四个View,这四个View的大小和位置都是一样的。self 是MMDrawerController 的对象。它们的层级结构就是:
self.view -> self.childControllerContainerView ->self.centerContainerView -> self.centerViewController.view。中央控制器的view在最上面,运行APP的时候,最先看到。###3.添加侧边控制器
(void)setDrawerViewController:(UIViewController )viewController forSide:(MMDrawerSide)drawerSide{
// 如果你添加的是中央控制器,程序就会崩溃。因为这个方法只能添加左右两边的控制器。
NSParameterAssert(drawerSide != MMDrawerSideNone);
// 这个方法,可以获得当前的左边或右边的控制器
UIViewController currentSideViewController = [self sideDrawerViewControllerForSide:drawerSide];
// 如果和原来的侧边视图控制器相同,就不必添加了
if (currentSideViewController == viewController) {
return;
}
// 如果原来已经有了侧边视图控制器,移除
if (currentSideViewController != nil) {
[currentSideViewController beginAppearanceTransition:NO animated:NO];
[currentSideViewController.view removeFromSuperview];
[currentSideViewController endAppearanceTransition];
[currentSideViewController willMoveToParentViewController:nil];
[currentSideViewController removeFromParentViewController];
}
// 添加新的侧边视图控制器
// 左边
UIViewAutoresizing autoResizingMask = 0;
if (drawerSide == MMDrawerSideLeft) {
_leftDrawerViewController = viewController;
autoResizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleHeight;}
// 右边
else if(drawerSide == MMDrawerSideRight){
_rightDrawerViewController = viewController;
autoResizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleHeight;
}
// viewController不为空,代表你想添加侧边控制器
if(viewController){
[self addChildViewController:viewController];
// 实例化的时候不走,直接看else里面的方法
if((self.openSide == drawerSide) &&
[self.childControllerContainerView.subviews containsObject:self.centerContainerView]){
[self.childControllerContainerView insertSubview:viewController.view belowSubview:self.centerContainerView];
[viewController beginAppearanceTransition:YES animated:NO];
[viewController endAppearanceTransition];
}
else{
// 添加新的侧边控制器
[self.childControllerContainerView addSubview:viewController.view];
[self.childControllerContainerView sendSubviewToBack:viewController.view];
[viewController.view setHidden:YES];
}
[viewController didMoveToParentViewController:self];
[viewController.view setAutoresizingMask:autoResizingMask];
//侧边栏的最大宽度默认280.
// H:代表self.view的高,W代表self.view的宽,w代表侧边栏的最大的宽度
// 左侧视图的frame: (0,0,w,H);右侧视图的frame: (W-w,0,w,H);
[viewController.view setFrame:viewController.mm_visibleDrawerFrame];
}
}
```
这篇文章介绍了MMDrawerController的实例化方法和各个控制器与视图的层级结构,下篇文章主要讲侧边栏的切换动画。如果喜欢就推荐一下吧!
转载于:https://www.cnblogs.com/doujiangyoutiao/p/6409108.html
iOS MMDrawerController源码解读(一)相关推荐
- iOS AOP 框架 - Aspects 源码解读
Aspects 是什么? Aspects 是 iOS 上的一个轻量级 AOP 库.它利用 method swizzling 技术为已有的类或者实例方法添加额外的代码,它是著名框架 PSPDFKit ( ...
- ios html zfplayer,【iOS】ZFPlayer源码解读中
前言 本篇继ZFPlayer源码解读基础之上,主要解析说明控制层与播放器,因为在上篇文章至现在并未提及丝毫关于这两个类业务的实现. 首先说下这两个类各自的职责. 控制层:主要负责响应与用户之间的交互, ...
- Alamofire源码解读系列(九)之响应封装(Response)
本篇主要带来Alamofire中Response的解读 前言 在每篇文章的前言部分,我都会把我认为的本篇最重要的内容提前讲一下.我更想同大家分享这些顶级框架在设计和编码层次究竟有哪些过人的地方?当然, ...
- AFNetworking 3.0 源码解读(一)之 AFNetworkReachabilityManager
做ios开发,AFNetworking 这个网络框架肯定都非常熟悉,也许我们平时只使用了它的部分功能,而且我们对它的实现原理并不是很清楚,就好像总是有一团迷雾在眼前一样. 接下来我们就非常详细的来读一 ...
- SnapKit 源码解读(五):Models
Models 里面的所有文件,都是用来对约束建模使用的. Typealiases Typealiases 为跨平台能力定义了一套公用的类. #if os(iOS) || os(tvOS)import ...
- Alamofire源码解读系列(十二)之请求(Request)
本篇是Alamofire中的请求抽象层的讲解 前言 在Alamofire中,围绕着Request,设计了很多额外的特性,这也恰恰表明,Request是所有请求的基础部分和发起点.这无疑给我们一个Req ...
- SnapKit 源码解读(一):Extensions
前言 iOS 开发中的布局方式,总体而言经过了三个时代.混沌初开之时,世间只有3.5英寸(iPhone 4.iPhone 4S),那个时候屏幕适配对于大多数 iOS 开发者来说并不是什么难题,用 fr ...
- Alamofire源码解读系列(七)之网络监控(NetworkReachabilityManager)
Alamofire源码解读系列(七)之网络监控(NetworkReachabilityManager) 本篇主要讲解iOS开发中的网络监控 前言 在开发中,有时候我们需要获取这些信息: 手机是否联网 ...
- underscore-1.8.3.js 源码解读全文注释版
// Underscore.js 1.8.3 // http://underscorejs.org // (c) 2009-2015 Jeremy Ashkenas, DocumentCloud an ...
最新文章
- 计算机网络实验可变长子网掩码,计算机网络实验3-子网掩码与划分子网实验报告.docx...
- 为什么插入数据普通PC比服务器更快?
- python绘图添加上下标
- COJ 1170 A Simple Problem
- Bootstrap的lia
- Bootstrap自适应居中问题
- apex英雄机器人探路者怎么玩_《王者荣耀》新英雄澜怎么玩 《王者荣耀》新英雄澜连招推荐...
- 拓端tecdat|R语言股票收益分布一致性检验KS检验Kolmogorov-Smirnov、置换检验Permutation Test可视化
- BigDecimal的add方法
- 高逼格!程序猿的表白也可以这么浪漫
- 读取ZIP文件时ZipEntry的size为-1的解决办法
- SAP中计划日历计算规则的理解
- 台达DVP-ES3 ModbusTCP通信案例
- 值得一看的纪录片——《河西走廊》墙裂推荐
- js和jsp的区别和联系
- 中文自然语言处理语言资源项目(ChineseNLPcorpus)
- win10定时关机c语言,小编为你win10系统通过命令实现定时关机的步骤
- 领导竟然在上班时间偷看这种网站...
- java基础:网络编程(一)简介
- 基于PIC18F458的CAN总线接口设计